如何约束模板参数

时间:2017-09-04 15:48:48

标签: c++ templates

我想创建一个只接受某些类型参数的模板。对于所有剩余类型,我希望产生编译时错误消息。所以我写下面的

------版本1 ------

template <typename T_,bool isError = true>
struct Error {
    static_assert(!isError, "Invalid Type");
};

template <typename T_>
struct Wrapper : Error <T_> {
private:
    T_ value_;
};

template <>
struct Wrapper<int> : Error<int, false> {
private:
    int value_;
};

int main()
{
    Wrapper<int> wi;
    Wrapper<long> wl;  // I get the Invalid Type.
}

由于我没有使用类型参数T_,我已将其删除,代码停止工作。

------第2版------

template <bool isError = true> 
struct Error {
    static_assert(!isError, "Invalid Type");
};

template <typename T_>
struct Wrapper : Error <> {
private:
    T_ value_;
};

template <>
struct Wrapper<int> : Error<false> {
private:
    int value_;
};

int main()
{
    Wrapper<int> wi;   // I get Invalid type ?????
    Wrapper<long> wl;  // I get the Invalid Type.
}

我的问题是。为什么在删除类型参数后会发生这种情况?这个解决方案“干净”吗?或者有更好的方法来实现我的意图?

1 个答案:

答案 0 :(得分:4)

一旦你有了:

template <typename T_>
struct Wrapper : Error <> {
private:
    T_ value_;
};

我们可以看到Error<>已完全指定(即,所有模板参数都已知),与之前仍然相关的情况不同。因此,编译器实际上将继续无条件地实例化Error<>,这意味着此代码永远不会编译(即使根本没有提到Wrapper)。当Error仍然依赖T时,它是一个依赖类型,因此只有在Wrapper<T>需要时才会实例化。

我可能会稍微区分出这个特征:

template <class T>
struct my_trait : std::false_type {};

template <>
struct my_trait<int> : std::true_type {};

template <class T>
struct Wrapper {
    static_assert(my_trait<T>::value, "");
};

int main()
{
    Wrapper<int> wi;
    Wrapper<long> wl;  // I get the Invalid Type.
}

如果您真的想重复使用错误消息,可以执行以下操作:

template <typename T>
struct Error {
    static_assert(my_trait<T>::value, "Invalid Type");
};

template <class T>
struct Wrapper {
  static constexpr auto unused = Error<T>{};
};