声明属于所有特化的 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.
我正在寻找的是一种表达方式:这对所有专业都是一样的:
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.