在函数模板重载解析期间,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?是否存在僵局和固有的语言缺陷?
答案 0 :(得分:6)
SFINAE根本不适用于异常规范,无论noexcept
是否属于函数类型。
参见[temp.deduct] / 7中的注释:
替换发生在所有使用的类型和表达式中 函数类型和模板参数声明。该 表达式不仅包括常量表达式,例如那些 出现在数组边界或非类型模板参数中,但也 sizeof内的一般表达式(即非常量表达式), decltype和其他允许非常量表达式的上下文。该 替换以词汇顺序进行,并在条件出现时停止 导致扣除失败的原因。 [注意:相当于 异常规范中的替换仅在以下情况下完成 实例化异常规范,此时如果替换导致无效类型或 表达。 - 结束记录]
P0012R1 didn't change anything就此而言。
Piotr的回答涵盖了代码的修复程序。
答案 1 :(得分:4)
如何限制构造函数?
#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)...}
{
}
};
答案 2 :(得分:2)
noexcept说明符的括号中的表达式是否参与 SFINAE在功能模板的重载解析期间?
它不参与模板推导,因为noexcept
说明符不是函数类型的一部分。
noexcept-specification不是函数类型的一部分。 (直到 C ++ 17)
因此,当推断出模板参数type
时,noexcept
不是推导类型的一部分。对于任何类型,您的编译器似乎都会返回true
,这就是为什么您无法检测它是否为noexcept
;这就是为什么一切都被接受的原因。
我遇到了同样的问题。你可以在这里查看我的问题/答案:
How can I detect whether a template argument is a noexcept function?
基本上,您唯一的选择是等待符合C ++ 17的编译器。