我想编写一个模板类MyClass
,该模板类接受正常和noexcept签名。例如MyClass<int()>
和MyClass<int() noexcept>
。
这是我尝试过的:
template<typename TSignature>
struct IsNoThrow;
template<typename TReturn, typename...TArgs>
struct IsNoThrow<TReturn(TArgs...)> {
static constexpr bool value = false;
};
template<typename TReturn, typename...TArgs>
struct IsNoThrow<TReturn(TArgs...) noexcept> {
static constexpr bool value = true;
};
template<typename T, bool = IsNoThrow<T>::value>
class MyClass;
template<bool BNoThrow, typename TReturn, typename...TParams>
class MyClass<TReturn(TParams...) noexcept(BNoThrow), BNoThrow> {
//VS2017(/std:c++latest) gives error C2057: expected constant expression
};
int main() {
MyClass<int()> mc;
}
为什么我收到该错误C2057?像我对MyClass
所做的那样,如何不专门对IsNoThrow
进行两次操作,怎么办?
答案 0 :(得分:1)
为什么我收到该错误C2057?像我使用IsNoThrow一样,如何在不两次专门化MyClass的情况下做到这一点?
我认为该错误是VC错误,但无论如何,您的解决方案似乎对我来说太复杂了。
我提议
(1)从IsNoThrow
和std::true_type
到std::false_type
的继承(以简化和使用std::integral_constant
中的工具)
template<typename TSignature>
struct IsNoThrow;
template<typename TReturn, typename...TArgs>
struct IsNoThrow<TReturn(TArgs...)> : public std::false_type
{ };
template<typename TReturn, typename...TArgs>
struct IsNoThrow<TReturn(TArgs...) noexcept> : public std::true_type
{ };
或者也许是simpy
template<typename TSignature>
struct IsNoThrow;
template<typename TReturn, typename...TArgs, bool B>
struct IsNoThrow<TReturn(TArgs...) noexcept(B)> : public std::integral_constant<bool, B>
{ };
(2)如果您对函数的返回类型和参数类型不感兴趣(但仅对拦截函数和检测它们是否抛出)感兴趣,则仅MyClass
的主类/结构(无专长)继承自IsNoThrow
template<typename T>
struct MyClass : public IsNoThrow<T>
{ };
仅当MyClass
类型为函数类型(T
导致编译错误)时,MyClass<int>
才进行编译,并从std::true_type
或std::false_type
继承noexcept
值。
#include <type_traits>
template<typename TSignature>
struct IsNoThrow;
template<typename TReturn, typename...TArgs>
struct IsNoThrow<TReturn(TArgs...)> : public std::false_type
{ };
template<typename TReturn, typename...TArgs>
struct IsNoThrow<TReturn(TArgs...) noexcept> : public std::true_type
{ };
template<typename T>
struct MyClass : public IsNoThrow<T>
{ };
int foo (int)
{ return 0; }
int bar (int) noexcept
{ return 0; }
int main()
{
static_assert( false == MyClass<decltype(foo)>::value );
static_assert( true == MyClass<decltype(bar)>::value );
static_assert( false == MyClass<int(int)>::value );
static_assert( true == MyClass<int(int) noexcept>::value );
//MyClass<int> mc; // compilaton error
}
如果您对返回值和参数类型感兴趣,在我看来您需要专门化,并且可能的解决方案是
template<typename T>
struct MyClass;
template<typename TReturn, typename ... TArgs, bool B>
struct MyClass<TReturn(TArgs...) noexcept(B)> : public std::integral_constant<bool, B>
{ };
-编辑-
如果您的VC编译器在推断noexcept(B)
中的布尔值时不支持C ++ 17,我想(假设您还需要推断出return和arguments类型)则需要两个{ 1}}专业化。
但是,如果您的问题是您必须重复此专业化的内容,那么我建议采用两种专业化的解决方案,其中第二个从第一个继承过来:
MyClass
这样,您就不需要template<typename T, bool = false>
struct MyClass;
template<typename TReturn, typename ... TArgs, bool B>
struct MyClass<TReturn(TArgs...), B> : public std::integral_constant<bool, B>
{ /* all common member/methods here */ };
template<typename TReturn, typename ... TArgs>
struct MyClass<TReturn(TArgs...) noexcept>
: public MyClass<TReturn(TArgs...), true>
{ /* empty: inherhit all from the other specialization */ };
了,您可以只开发第一个专业化:所有成员和方法都继承自另一个专业化。
以下是完整的编译示例
IsNoThrow