模板接受具有一种专业化的 throw 和 nothrow
template accept both throw and nothrow with one specialization
我想写一个模板 class 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?如果不像 IsNoThrow
那样专门化 MyClass
两次,我怎么能做到这一点?
Why I got that error C2057? How can I do it without specializing MyClass twice like I did with IsNoThrow?
我想这个错误是一个 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) 如果您对函数的 return 类型和参数类型不感兴趣(但仅在拦截函数并检测它们是否抛出或不抛出时)只有一个 main class/struct for 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
}
如果您对 return 和参数类型感兴趣,在我看来您需要专业化,可能的解决方案是
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 和参数类型)你需要两个 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
}
我想写一个模板 class 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?如果不像 IsNoThrow
那样专门化 MyClass
两次,我怎么能做到这一点?
Why I got that error C2057? How can I do it without specializing MyClass twice like I did with IsNoThrow?
我想这个错误是一个 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) 如果您对函数的 return 类型和参数类型不感兴趣(但仅在拦截函数并检测它们是否抛出或不抛出时)只有一个 main class/struct for 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
}
如果您对 return 和参数类型感兴趣,在我看来您需要专业化,可能的解决方案是
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 和参数类型)你需要两个 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
}