我需要某种类型的特质:
template<typename T> struct foo {};
template<>
struct foo<char> { static constexpr char c = 'c' };
如果我需要c
类型的字符char
,但在以下情况下不会出现这种情况,则效果非常好:
printf("%c", foo<const char>::c);
是否有更优雅的方法来执行此操作,而不是以相同的方式为char
和const char
指定模板?
答案 0 :(得分:5)
添加部分专业化:
template <class T> struct foo<const T> : foo<T> {};
答案 1 :(得分:3)
除了T.C。的正确答案之外,如果你需要这种结构,你可以使用以下内容。我不知道这是不是一个成语,但我发现它非常有用。
#include <iostream>
#include <type_traits>
template <typename>
class TraitImpl;
template <typename T>
using Trait = TraitImpl<std::remove_const_t<T>>;
template <>
class TraitImpl<char>
{
public:
static constexpr char value = 'c';
};
int main()
{
std::cout << Trait<char>::value << std::endl;
std::cout << Trait<const char>::value << std::endl;
}
基本上,您将Trait
定义为TraitImpl
的别名,但TraitImpl
的模板参数是Trait
模板参数的修改类型。如果您还需要volatile char
等使用特征类的相同实现,则可以将remove_const
替换为remove_cv
。如果您需要有符号或无符号整数来使用相同的特征类,则同样如此。这种别名的使用有很多可能性。如果您仅限于C ++ 11,请将remove_const_t<T>
替换为typename remove_const<T>::type
。如果您仅限于C ++ 98,请将类型别名替换为公共继承,并使用Boost类型特征或编写自己的特征,这在这些简单的情况下很容易。
答案 2 :(得分:3)
另一种方法是使用部分特化和第二个模板参数和默认值
它比其他解决方案更灵活,因为您可以轻松使用type_traits
中的其他特征来调整接受的类型。
它遵循一个最小的工作示例:
#include<type_traits>
template<typename T, typename U = std::remove_const_t<T>>
struct S;
template<typename T>
struct S<T, char> { static constexpr char c = 'c'; };
int main() {
static_assert(S<const char>::c == 'c', "!");
static_assert(S<char>::c == 'c', "!");
}
您可以注意到,它不需要为const
或其他任何内容添加额外的专业化
基本思想是使用你已定义的那个。
作为旁注,如果您想将建议的解决方案扩展到所有其他类型,您可以简单地使用此专业化而不是上面的那个:
template<typename T>
struct S<T> {
// ...
};
它遵循一个最小的工作示例:
#include<type_traits>
template<typename T, typename U = std::decay_t<T>>
struct S;
template<typename T>
struct S<T> { static constexpr char c = 'c'; };
struct U {};
int main() {
static_assert(S<const U &>::c == 'c', "!");
static_assert(S<U>::c == 'c', "!");
}