Учитывая, возможно, тип функции Varargs с возможно резюме-спецификатор-сл и, возможно, реф-классификатор, Можно ли написать черту типа, которая удаляет все квалификаторы без записи 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)
И с новая транзакционная память TS добавление transaction_safe
для смеси, это означает, что нам нужно написать 48 частичных специализаций для этого?
редактировать: Цитируем описание этих странных типов функций ([dcl.fct] / p6, цитируем N4140):
Тип функции с резюме-спецификатор-сл или реф-классификатор
(включая тип с именем typedef-name (7.1.3, 14.1))
только как:[ пример:
- тип функции для нестатической функции-члена,
- тип функции, к которой относится указатель на член,
- тип функции верхнего уровня объявления typedef функции или псевдоним декларации,
- тип-идентификатор в аргументе по умолчанию для параметра типа (14.1), или
- тип-идентификатор из Шаблон-аргумент для типа параметра (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-квалификации поверх
тип функции. В последнем случае CV-классификаторы игнорируются
[Заметка: тип функции, который имеет резюме-спецификатор-сл это не
cv-квалифицированный тип; нет cv-квалифицированных типов функций. — конец
нота ] [ пример:typedef void F(); struct S { const F f; // OK: equivalent to: void f(); };
— конец примера ]
Тип возврата, Параметр типа-лист,
реф-классификатор, и резюме-спецификатор-сл, но не аргументы по умолчанию (8.3.6) или спецификация исключения (15.4), являются частью
тип функции. [Заметка: Типы функций проверяются во время
присваивания и инициализации указателей на функции, ссылки
на функции, и указатели на функции-члены. — конечная нота ]
Я не вижу возможности обойти это — определите это один раз и используйте его всякий раз, когда это возможно.
Такое огромное количество специализаций можно избежать, когда квалификаторы верхний уровень — мы могли бы использовать 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((,...))
демонстрация.
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_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))>; \
};