输入`type`和`const type`的特征

时间:2016-12-11 15:26:17

标签: c++ templates

我需要某种类型的特质:

template<typename T> struct foo {};
template<>
struct foo<char> { static constexpr char c = 'c' };

如果我需要c类型的字符char,但在以下情况下不会出现这种情况,则效果非常好:

printf("%c", foo<const char>::c);

是否有更优雅的方法来执行此操作,而不是以相同的方式为charconst char指定模板?

3 个答案:

答案 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', "!");
}