3

次のようなメタ関数があるとします。

template<typename LHS , typename RHS>
struct add;

また、既知の型に対する特殊化のセットがあります。たとえば、統合ラッパー:

template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2>
struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2> : public std::integral_constant<std::common_type_t<T1,T2>,VALUE1+VALUE2> {}; //Take advantage of C++14 helpers

数日前、新しいクラスを作成し、このクラスの足し算を特殊化しました。

template<typename X , typename Y>
struct point_2d
{
    using x = X;
    using y = Y;
};

template<typename X1 , typename Y1 , typename X2 , typename Y2>
struct add<point_2d<X1,Y1>,ppoint_2d<X2,Y2>> : public point_2d<add<X1,X2>,add<Y1,Y2>> {};

ご覧のとおり、メタ関数を使用addして座標の追加を実行しました。そのため、メタ関数の追加に特化した任意の型をpoint_2d座標として使用できます。

私の質問は次のとおりです。テンプレートに特定の型を引数として持つ特殊化があるかどうかを確認する方法はありますか?

このようなもの:

template<template<typename...> class TEMPLATE , typename... Ts>
struct has_specialization;

template<template<typename...> class TEMPLATE , typename... Ts>
struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> exists */ , Ts...> : public std::true_type {};

template<template<typename...> class TEMPLATE , typename... Ts>
struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> doesn't exists */ , Ts...> : public std::false_type {};
4

1 に答える 1

7

@BartekBanachewiczのアイデアは、アサートを通じてユーザーフレンドリーなコンパイラエラーを提供することです。渡された座標が追加可能かどうか (point_2d の例に従って) を確認できる場合 (つまり、add メタ関数の特殊化がその座標に対して定義されているか定義されていないか)、「その座標は追加できません。point_2dポイントを追加するには、追加可能な座標が必要です」、一般的な恐ろしいテンプレートのインスタンス化エラーの代わりに。

これがあなたの質問の動機であることを考えると、これはより簡単で直接的な解決策ではありません:

#include <type_traits>

template<typename LHS , typename RHS>
using cannot_add =  std::integral_constant<bool,std::is_same<LHS,LHS>::value>;

template<typename LHS , typename RHS>
struct add
{
    /* Assert some expressively named condition that is always false 
        but is dependent on a template parameter.
    */
    static_assert(!cannot_add<LHS,RHS>::value,
        "Types are not addable. Need specialization");
};

template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2>
struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2>> 
: public std::integral_constant<
    typename std::common_type<T1,T2>::type,
    VALUE1+VALUE2
> {};  

int main()
{
    add<std::integral_constant<int,1>,std::integral_constant<int,2>> x; // Line 25 
    add<float,float> y; // Line 26
    return 0;
}

GCC 4.8.1 の診断:

main.cpp:26:19:   required from here
main.cpp:12:2: error: static assertion failed: Types are not addable. Need specialization

Clang 3.3 診断:

main.cpp:12:2: error: static_assert failed "Types are not addable. Need specialization"
    static_assert(!cannot_add<LHS,RHS>::value,
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:26:19: note: in instantiation of template class 'add<float, float>' requested here
    add<float,float> y; // Line 26
                 ^
于 2013-07-29T06:48:56.343 に答える