给定一个可能的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)
如果the new transactional memory TS添加了transaction_safe
,那是否意味着我们需要为此编写48个部分专精?
编辑:引用这些奇怪的函数类型的描述([dcl.fct] / p6,引用N4140):
具有 cv-qualifier-seq 或 ref-qualifier 的函数类型 (包括typedef-name(7.1.3,14.1)命名的类型)将出现 仅作为:
- 非静态成员函数的函数类型
- 指向成员的指针引用的函数类型
- 函数typedef声明的顶级函数类型或 alias-declaration ,
- type-id 在type-parameter(14.1)的默认参数中,或
- type-parameter 的 type-id type-parameter (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-qualifiers 。 [注意:具有 cv-qualifier-seq 的函数类型不是 cv-qualified类型;没有cv限定的函数类型。 - 结束 注意] [示例:
typedef void F(); struct S { const F f; // OK: equivalent to: void f(); };
- 结束示例]
返回类型,参数类型列表 ,. ref-qualifier 和 cv-qualifier-seq ,但不是默认参数(8.3.6)或异常规范(15.4),是 函数类型。 [注意:在期间检查函数类型 指向函数,引用的指针的赋值和初始化 到函数,以及指向成员函数的指针。 - 结束记录]
答案 0 :(得分:8)
我认为没办法 - 定义一次并尽可能重复使用
当限定符顶级时,可以避免如此大量的特化 - 在这种情况下我们可以使用std::remove_cv
或std::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((,...))
Demo。
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))
Demo。在添加transaction_safe
或transaction_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))>; \
};