2017-09-04 39 views
3

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

------ 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

你即使没有遇到错误'无线/ wl'。因为'Error'被实例化。 – Jarod42

+2

当你移除'T_'时,''Wrapper''模板的基类'Error <>'不再依赖于模板参数,所以它不需要实例化'Wrapper '本身。正如Joard指出的那样,即使你有一个空的'main',你也会遇到错误。 – Praetorian

回答

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>{}; 
}; 
+0

谢谢。你的建议显然更具可读性且不太冗长。 –

+0

@JacintoResende谢谢。如果你觉得这个问题完全可以回答你的问题,你可以接受它,以便人们知道这个问题不需要进一步的答案。 –