为什么我收到 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
{ };
或者,也许,简单
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> 给出编译错误)并根据noexcept 值从std::true_type 或std::false_type 继承。
#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,我想(鉴于您还需要推断返回和参数类型)您需要两个 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,你可以只开发第一个特化:其中的所有成员和方法都继承自另一个特化。
以下是完整的编译示例
#include <type_traits>
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 */
static constexpr bool isNoExcept ()
{ return B; }
};
template<typename TReturn, typename ... TArgs>
struct MyClass<TReturn(TArgs...) noexcept>
: public MyClass<TReturn(TArgs...), true>
{ /* empty: inherhit all from the other specialization */ };
int foo (int)
{ return 0; }
int bar (int) noexcept
{ return 0; }
int main()
{
// using value
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 );
// using isNoExcept()
static_assert( false == MyClass<decltype(foo)>::isNoExcept() );
static_assert( true == MyClass<decltype(bar)>::isNoExcept() );
static_assert( false == MyClass<int(int)>::isNoExcept() );
static_assert( true == MyClass<int(int) noexcept>::isNoExcept() );
//MyClass<int> mc; // compilaton error
}