我想创建一个只接受某些类型参数的模板。对于所有剩余类型,我希望产生编译时错误消息。所以我写下面的
------版本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.
}
我的问题是。为什么在删除类型参数后会发生这种情况?这个解决方案“干净”吗?或者有更好的方法来实现我的意图?
答案 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>{};
};