声明属于所有特化的 class 模板成员

Declaring a class template member that belongs to all specializations

我正在寻找的是一种表达方式:这对所有专业都是一样的:

template <typename T>
struct Foo {
  using id_type = unsigned int; // this does not depend on T!
};

Foo::id_type theId; // Doesn't matter what the specialization is, id_type is always the same.

我想访问 id_type 而无需指定专业...

你不可能得到你想要的。 Foo 不是 class。 Foo<T> 是一个 class,对于任何 T

您可以拥有一个包含 id_type

的非模板库
struct FooBase {
  using id_type = unsigned int;
};

template <typename T>
struct Foo : FooBase{};

FooBase::id_type theId;

您可以为 T

提供默认参数
template <typename T = struct FooPlaceholder>
struct Foo {
  using id_type = unsigned int; // this does not depend on T!
};

Foo<>::id_type theId;

然而,没有什么能阻止我编写缺少(或重新定义)id_type.

Foo 的显式专业化
template <> struct Foo<MyType> { };    
template <> struct Foo<MyOtherType> { int id_type = 42; };

只是基于 Caleth 的回答和随之而来的评论的扩展。 您可以像这样保护自己免受 Foo 的“不良”专业化:

#include <iostream>
#include <type_traits>

//-------------------------------------------------------------------------
// from Caleth

struct FooBase
{
    using id_type = unsigned int;
};

template <typename T>
struct Foo : FooBase 
{
};

FooBase::id_type theId{};

//-------------------------------------------------------------------------
// specialization bypassing FooBase 

template<>
struct Foo<char>
{
};

//-------------------------------------------------------------------------
// compile time check if someone mad a "bad" specialization, pre C++20

template<typename T>
void f(const Foo<T>& foo)
{
    static_assert(std::is_base_of_v<FooBase, Foo<T>>); 
}

//-------------------------------------------------------------------------
// C++20 concept to check for FooBase

template<typename T>
concept HasFooBase = std::is_base_of_v<FooBase, T>;

// only accepts types derived from FooBase
void g(const HasFooBase auto& foo)
{
}

//-------------------------------------------------------------------------

int main()
{
    Foo<int> foo;
    Foo<char> bar;

    f(foo);
    g(foo);

    f(bar); // won't compile, error C2607: static assertion failed
    g(bar); // won't compile, error C7602: 'g': the associated constraints are not satisfied

    return 0;
}

而不是 id_type 作为 class(别名声明)属性,您可以使它成为模板模板参数上的独立特征:

#include <type_traits>

// Helper: compare with std::is_same but for
//         template template parameter type arguments.
template <template <typename> typename, template <typename> typename>
struct is_same_primary_template : std::false_type {};

template <template <typename> typename TT>
struct is_same_primary_template<TT, TT> : std::true_type {};

template <template <typename> typename TT, template <typename> typename UU>
constexpr bool is_same_primary_template_v{
    is_same_primary_template<TT, UU>::value};

template <typename T> struct Foo {};

template <template <typename> typename, typename Enable = void> struct id_type;

template <template <typename> typename TT>
struct id_type<TT, std::enable_if_t<is_same_primary_template_v<TT, Foo>>> {
  using type = int;
};

// ...

template <template <typename> typename TT>
using id_type_t = typename id_type<TT>::type;

int main() { id_type_t<Foo> theId; }

不过,这种方法有一个缺点。由于 trait 专门针对特定类型,因此它将这些类型与 trait 的实现相结合(如 want be very careful with the location of your specializations、w.r.t。主模板的位置)。

When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.