簡體   English   中英

從函數類型中剝離所有限定符

[英]Stripping all qualifiers from a function type

給定一個可能的varargs函數類型,可能有cv-qualifier-seq和可能的ref-qualifier ,是否可以編寫一個類型特征來剝離所有限定符而不編寫4 * 3 * 2 = 24個部分特化?

template<class T>
struct strip_function_qualifiers;

template<class R, class... Args>
struct strip_function_qualifiers<R(Args...)> { using type = R(Args...); };

template<class R, class... Args>
struct strip_function_qualifiers<R(Args..., ...)> { using type = R(Args..., ...); };

template<class R, class... Args>
struct strip_function_qualifiers<R(Args...) const> { using type = R(Args...); };

template<class R, class... Args>
struct strip_function_qualifiers<R(Args..., ...) const > { using type = R(Args..., ...); };

template<class R, class... Args>
struct strip_function_qualifiers<R(Args...) const &> { using type = R(Args...); };

template<class R, class... Args>
struct strip_function_qualifiers<R(Args..., ...) const & > { using type = R(Args..., ...); };

// etc. etc. for each possible combination (24 in total)

並且使用新的事務內存TStransaction_safe添加到混合中,這是否意味着我們需要為此編寫48個部分特化?


編輯 :引用這些奇怪的函數類型的描述([dcl.fct] / p6,引用N4140):

具有cv-qualifier-seqref-qualifier (包括由typedef-name(7.1.3,14.1)命名的類型)的函數類型應僅顯示為:

  • 非靜態成員函數的函數類型,
  • 指向成員的指針引用的函數類型,
  • 函數typedef聲明或別名聲明的頂級函數類型,
  • type-parameter(14.1)的默認參數中的type-id ,或
  • type-parameter模板參數type-id (14.3.1)。

[ 例如

 typedef int FIC(int) const; FIC f; // ill-formed: does not declare a member function struct S { FIC f; // OK }; FIC S::*pm = &S::f; // OK 

- 結束例子 ]

cv-qualifier-seq在函數聲明中的作用與在函數類型之上添加cv-qualification不同。 在后一種情況下,忽略cv限定符 [ 注意 :具有cv-qualifier-seq的函數類型不是cv限定類型; 沒有cv限定的函數類型。 - 尾注 ] [ 示例

  typedef void F(); struct S { const F f; // OK: equivalent to: void f(); }; 

- 結束例子 ]

返回類型, 參數類型列表ref限定符cv-qualifier-seq ,但不是默認參數(8.3.6)或異常規范(15.4),是函數類型的一部分。 [ 注意 :在指向函數的指針和函數的引用以及指向成員函數的指針的賦值和初始化期間,將檢查函數類型。 - 結束說明 ]

我認為沒辦法 - 定義一次並盡可能重復使用它。
當限定符為頂級時,可以避免如此大量的特化 - 在這種情況下我們可以使用std::remove_cvstd::remove_reference ,在每個步驟中刪除所有正交限定符。 遺憾的是,這不適用於您引用的段落中解釋的功能:例如,cv-qualifier是函數類型的一部分,而不是頂級。 void() const是一個與void()根本不同的類型,因此兩者必須由兩個不同的部分特化匹配。

您可以使用宏縮短所有特化:

#define REM_CTOR(...) __VA_ARGS__

#define SPEC(var, cv, ref) \
template <typename R, typename... Args> \
struct strip_function_qualifiers<R(Args... REM_CTOR var) cv ref > \
{using type = R(Args... REM_CTOR var);};

#define REF(var, cv) SPEC(var, cv,) SPEC(var, cv, &) SPEC(var, cv, &&)

#define CV(var) REF(var,) REF(var, const) \
                REF(var, volatile) REF(var, const volatile)

template <typename> struct strip_function_qualifiers;

CV(()) CV((,...))

演示
Boost.PP也是可能的:

#include <boost/preprocessor/tuple/enum.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/for_each_product.hpp>

#define REF  (&&)(&)()
#define CV   (const volatile)(const)(volatile)()
#define VAR  (())((,...)) // Had to add a comma here and use rem_ctor below,
                          // otherwise Clang complains about ambiguous ellipses

#define SPEC(r, product) \
template <typename R, typename... Args> \
struct strip_function_qualifiers<R(Args... BOOST_PP_TUPLE_ENUM( \
    BOOST_PP_SEQ_ELEM(0, product))) \
    BOOST_PP_SEQ_ELEM(1, product)   \
    BOOST_PP_SEQ_ELEM(2, product)>  \
{using type = R(Args... BOOST_PP_TUPLE_ENUM(BOOST_PP_SEQ_ELEM(0, product)));};

template <typename> struct strip_function_qualifiers;

BOOST_PP_SEQ_FOR_EACH_PRODUCT(SPEC, (VAR)(CV)(REF))

演示 添加新限定符(例如transaction_safetransaction_safe_noinherit時,這兩種方法都不會長得多。


這是一個修改過的SPEC ,它也定義了某些特征成員。

#include <type_traits>

#include <boost/preprocessor/tuple/size.hpp>

// […]

#define SPEC(r, product)                                         \
template <typename R, typename... Args>                          \
struct strip_function_qualifiers<R(Args... BOOST_PP_TUPLE_ENUM(  \
    BOOST_PP_SEQ_ELEM(0, product))) \
    BOOST_PP_SEQ_ELEM(1, product)   \
    BOOST_PP_SEQ_ELEM(2, product)>  \
{                                     \
    using type = R(Args... BOOST_PP_TUPLE_ENUM(BOOST_PP_SEQ_ELEM(0, product))); \
                                                            \
private:                                                    \
    using cv_type = int BOOST_PP_SEQ_ELEM(1, product);      \
    using ref_type = int BOOST_PP_SEQ_ELEM(2, product);     \
public:                                                     \
    using is_const    = std::is_const<cv_type>;             \
    using is_volatile = std::is_volatile<cv_type>;          \
    using is_ref_qualified = std::is_reference<ref_type>;               \
    using is_lvalue_ref_qualified = std::is_lvalue_reference<ref_type>; \
    using is_rvalue_ref_qualified = std::is_rvalue_reference<ref_type>; \
    using is_variadic = std::integral_constant<bool,                          \
                       !!BOOST_PP_TUPLE_SIZE(BOOST_PP_SEQ_ELEM(0, product))>; \
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM