从函数类型中剥离所有限定符
Stripping all qualifiers from a function type
给定一个可能带有 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):
A function type with a cv-qualifier-seq or a ref-qualifier
(including a type named by typedef-name (7.1.3, 14.1)) shall appear
only as:
- the function type for a non-static member function,
- the function type to which a pointer to member refers,
- the top-level function type of a function typedef declaration or alias-declaration,
- the type-id in the default argument of a type-parameter (14.1), or
- the type-id of a template-argument for a type-parameter (14.3.1).
[ Example:
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
— end example ]
The effect of a cv-qualifier-seq in a function
declarator is not the same as adding cv-qualification on top of the
function type. In the latter case, the cv-qualifiers are ignored.
[Note: a function type that has a cv-qualifier-seq is not a
cv-qualified type; there are no cv-qualified function types. — end
note ] [ Example:
typedef void F();
struct S {
const F f; // OK: equivalent to: void f();
};
— end example ]
The return type, the parameter-type-list, the
ref-qualifier, and the cv-qualifier-seq, but not the default arguments (8.3.6) or the exception specification (15.4), are part of
the function type. [Note: Function types are checked during the
assignments and initializations of pointers to functions, references
to functions, and pointers to member functions. — end note ]
我看不出解决这个问题的方法 - 定义一次并尽可能重用它。
当限定符是 top-level 时,可以避免如此大量的特化 - 在这种情况下我们可以使用 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))>; \
};
给定一个可能带有 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):
A function type with a cv-qualifier-seq or a ref-qualifier (including a type named by typedef-name (7.1.3, 14.1)) shall appear only as:
- the function type for a non-static member function,
- the function type to which a pointer to member refers,
- the top-level function type of a function typedef declaration or alias-declaration,
- the type-id in the default argument of a type-parameter (14.1), or
- the type-id of a template-argument for a type-parameter (14.3.1).
[ Example:
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
— end example ]
The effect of a cv-qualifier-seq in a function declarator is not the same as adding cv-qualification on top of the function type. In the latter case, the cv-qualifiers are ignored. [Note: a function type that has a cv-qualifier-seq is not a cv-qualified type; there are no cv-qualified function types. — end note ] [ Example:
typedef void F(); struct S { const F f; // OK: equivalent to: void f(); };
— end example ]
The return type, the parameter-type-list, the ref-qualifier, and the cv-qualifier-seq, but not the default arguments (8.3.6) or the exception specification (15.4), are part of the function type. [Note: Function types are checked during the assignments and initializations of pointers to functions, references to functions, and pointers to member functions. — end note ]
我看不出解决这个问题的方法 - 定义一次并尽可能重用它。
当限定符是 top-level 时,可以避免如此大量的特化 - 在这种情况下我们可以使用 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))>; \
};