std :: is_same_v с неспециализированным шаблоном - PullRequest
1 голос
/ 18 января 2020

У меня есть следующий код:

#include <iostream>
#include <type_traits>

using namespace std;

template<typename T, int N>
class A {
public:
    static constexpr int n = N;
};

template<typename T, typename X, int N>
class B {
public:
    static constexpr int x = N;
};

template<typename T>
void test(T) {
    if constexpr (std::is_same_v<T, A>) {
        int a = T::n;
    } else if constexpr (std::is_same_v<T, B>) {
        int a = T::x;
    }
    cout << "a";
};

int main()
{
    A<int, 2> a;
    test(a);
    return 0;
}

Компиляция приводит к следующей ошибке:

error: type/value mismatch at argument 2 in template parameter list for ‘template<class _Tp, class _Up> constexpr const bool std::is_same_v<_Tp, _Up>’
   20 |     if constexpr (std::is_same_v<T, A>) {
      |                   ~~~~~^~~~~~~~~~~~~~~
note:   expected a type, got ‘A’

Проблема в том, что я не могу использовать правильный тип здесь (например, A), так как я не знаю, каковы параметры шаблона или сколько их. По сути, я хочу сопоставить любой тип класса A с любыми аргументами шаблона.

Ответы [ 2 ]

5 голосов
/ 18 января 2020

Для этого вам нужно написать свою собственную черту:

template<typename>
struct is_specialization_of_A : std::false_type {};

template<typename T, int N>
struct is_specialization_of_A<A<T,N>> : std::true_type {};

template<typename T>
inline constexpr auto is_specialization_of_A_v = is_specialization_of_A<T>::value;

и аналогично для B.

Вы также можете использовать шаблон как параметр шаблона шаблона для черты, так что вам нужно только одно определение признака, но оно работает только до тех пор, пока категории параметров шаблона совпадают. Здесь это не так (A имеет <type, non-type>, в то время как B имеет <type, type, non-type>).

template<typename, template<typename, auto> class>
struct is_specialization_of : std::false_type {};

template<template<typename, auto> class Tmpl, typename T, auto N>
struct is_specialization_of<Tmpl<T, N>, Tmpl> : std::true_type {};

template<typename T, template<typename, auto> class Tmpl>
inline constexpr auto is_specialization_of_v = is_specialization_of<Tmpl, T>::value;

Это можно использовать как is_specialization_of_v<A, T>, но не is_specialization_of_v<B, T>.

3 голосов
/ 18 января 2020

Если у вас много шаблонов классов, таких как A и B, вы можете определить черту одного типа, которая будет возвращать «тег»:

struct tag_A {};
struct tag_B {};

template<class>
struct get_tag {
    using type = void;
};

template<typename T, int N>
struct get_tag<A<T, N>> {
    using type = tag_A;
};

template<typename T, typename X, int N>
struct get_tag<B<T, X, N>> {
    using type = tag_B;
};

template<typename T>
void test(T) {
    using tag = typename get_tag<T>::type;
    if constexpr (std::is_same_v<tag, tag_A>) {
        // ...
    } else if constexpr (std::is_same_v<tag, tag_B>) {
        // ...
    }
}
...