SFINAE 和 noexcept 说明符
SFINAE and noexcept specifier
noexcept
说明符括号中的表达式在函数模板重载解析期间是否参与 SFINAE?
我想为聚合创建一个包装器,并希望 std::is_constructible
谓词能够正常工作:
template< typename type >
struct embrace
: type
{
template< typename ...arguments >
embrace(arguments &&... _arguments) noexcept(noexcept(type{std::forward< arguments >(_arguments)...}))
: type{std::forward< arguments >(_arguments)...} // braces
{ ; }
};
int
main()
{
struct S { int i; double j; }; // aggregate
using E = embrace< S >;
E b(1, 1.0); // "parentheses"-constructible => can be used as usual types
b.i = 1; b.j = 2.0; // accessible
static_assert(std::is_constructible< E, int, double >{});
static_assert(std::is_constructible< E, struct B >{}); // want hard error here
return EXIT_SUCCESS;
}
但是我在 noexcept
规范中使用 noexcept
运算符来启用 SFINAE 的尝试失败了,模板化构造函数接受传递给它的所有内容。怎么限制构造函数?
标准不允许特化来自 <type_traits>
的任何谓词。一般如何处理接受可变模板参数包和 SFINAE 的 c-tors?是否存在僵局和固有的语言缺陷?
Does an expression in noexcept specifier's parentheses participate in
SFINAE during overload resolution of function templates?
它不参与模板推导,因为 noexcept
说明符不是函数类型的一部分。
The noexcept-specification is not a part of the function type. (until
C++17)
因此,当推导模板参数 type
时,noexcept
不是推导类型的一部分。您的编译器似乎 return true
对于任何类型,这就是为什么您无法检测它是否是 noexcept
的原因;这就是为什么一切都被接受的原因。
我运行进入同样的问题。你可以在这里查看我的question/answer:
基本上,您唯一的选择是等待 C++17 兼容的编译器。
How can the constructor be restricted?
#include <utility>
template <typename type>
struct embrace : type
{
template <typename... arguments
, typename = decltype(type{std::declval<arguments>()...})>
embrace(arguments&&... _arguments)
noexcept(noexcept(type{std::forward<arguments>(_arguments)...}))
: type{std::forward<arguments>(_arguments)...}
{
}
};
(或更短):
#include <utility>
template <typename type>
struct embrace : type
{
template <typename... arguments
, bool NoExcept = noexcept(type{std::declval<arguments>()...})>
constexpr
embrace(arguments&&... _arguments)
noexcept(NoExcept)
: type{std::forward<arguments>(_arguments)...}
{
}
};
SFINAE 根本不适用于 异常规范 ,无论 noexcept
是否属于函数类型。
参见 [temp.deduct]/7 中的注释:
The substitution occurs in all types and expressions that are used in
the function type and in template parameter declarations. The
expressions include not only constant expressions such as those that
appear in array bounds or as nontype template arguments but also
general expressions (i.e., non-constant expressions) inside sizeof,
decltype, and other contexts that allow non-constant expressions. The
substitution proceeds in lexical order and stops when a condition that
causes deduction to fail is encountered. [ Note: The equivalent
substitution in exception specifications is done only when the
exception-specification is instantiated, at which point a program is ill-formed if the substitution results in an invalid type or
expression. —end note ]
P0012R1 didn't change anything这方面
Piotr 的回答涵盖了对您的代码的修复。
noexcept
说明符括号中的表达式在函数模板重载解析期间是否参与 SFINAE?
我想为聚合创建一个包装器,并希望 std::is_constructible
谓词能够正常工作:
template< typename type >
struct embrace
: type
{
template< typename ...arguments >
embrace(arguments &&... _arguments) noexcept(noexcept(type{std::forward< arguments >(_arguments)...}))
: type{std::forward< arguments >(_arguments)...} // braces
{ ; }
};
int
main()
{
struct S { int i; double j; }; // aggregate
using E = embrace< S >;
E b(1, 1.0); // "parentheses"-constructible => can be used as usual types
b.i = 1; b.j = 2.0; // accessible
static_assert(std::is_constructible< E, int, double >{});
static_assert(std::is_constructible< E, struct B >{}); // want hard error here
return EXIT_SUCCESS;
}
但是我在 noexcept
规范中使用 noexcept
运算符来启用 SFINAE 的尝试失败了,模板化构造函数接受传递给它的所有内容。怎么限制构造函数?
标准不允许特化来自 <type_traits>
的任何谓词。一般如何处理接受可变模板参数包和 SFINAE 的 c-tors?是否存在僵局和固有的语言缺陷?
Does an expression in noexcept specifier's parentheses participate in SFINAE during overload resolution of function templates?
它不参与模板推导,因为 noexcept
说明符不是函数类型的一部分。
The noexcept-specification is not a part of the function type. (until C++17)
因此,当推导模板参数 type
时,noexcept
不是推导类型的一部分。您的编译器似乎 return true
对于任何类型,这就是为什么您无法检测它是否是 noexcept
的原因;这就是为什么一切都被接受的原因。
我运行进入同样的问题。你可以在这里查看我的question/answer:
基本上,您唯一的选择是等待 C++17 兼容的编译器。
How can the constructor be restricted?
#include <utility>
template <typename type>
struct embrace : type
{
template <typename... arguments
, typename = decltype(type{std::declval<arguments>()...})>
embrace(arguments&&... _arguments)
noexcept(noexcept(type{std::forward<arguments>(_arguments)...}))
: type{std::forward<arguments>(_arguments)...}
{
}
};
(或更短):
#include <utility>
template <typename type>
struct embrace : type
{
template <typename... arguments
, bool NoExcept = noexcept(type{std::declval<arguments>()...})>
constexpr
embrace(arguments&&... _arguments)
noexcept(NoExcept)
: type{std::forward<arguments>(_arguments)...}
{
}
};
SFINAE 根本不适用于 异常规范 ,无论 noexcept
是否属于函数类型。
参见 [temp.deduct]/7 中的注释:
The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions. The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered. [ Note: The equivalent substitution in exception specifications is done only when the exception-specification is instantiated, at which point a program is ill-formed if the substitution results in an invalid type or expression. —end note ]
P0012R1 didn't change anything这方面
Piotr 的回答涵盖了对您的代码的修复。