模板通过一个专门化同时接受throw和nothrow

template accept both throw and nothrow with one specialization

本文关键字:throw nothrow 专门化 一个      更新时间:2023-10-16

我想编写一个同时接受普通签名和非异常签名的模板类MyClass。例如CCD_ 2和CCD_。

这就是我尝试过的:

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?如果不像使用IsNoThrow那样两次专门化MyClass,我怎么能做到这一点?

为什么我得到错误C2057?我怎么能在不像IsNoThrow那样两次专门化MyClass的情况下做到这一点?

我想这个错误是VC错误,但无论如何,你的解决方案对我来说似乎过于复杂了。

我建议

(1) 从std::true_typestd::false_type继承IsNoThrow(以简化和使用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) 如果你对函数的返回类型和参数类型不感兴趣(但只对拦截函数和检测它们是否抛出),那么只对继承自IsNoThrowMyClass的主类/结构(没有专门化)感兴趣

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 */ };

这样,您就不需要MyClass<int()>0,并且只能开发第一个专业化:其中的所有成员和方法都继承自另一个专业化。

以下是的完整编译示例

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