SFINAE和noexcept说明符

时间:2015-11-12 05:50:30

标签: c++ c++11 constructor c++14 sfinae

在函数模板重载解析期间,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?是否存在僵局和固有的语言缺陷?

3 个答案:

答案 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)...}
    {
    }
};

DEMO

(或更短):

#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)...}
    {
    }
};

DEMO 2

答案 2 :(得分:2)

  

noexcept说明符的括号中的表达式是否参与   SFINAE在功能模板的重载解析期间?

它不参与模板推导,因为noexcept说明符不是函数类型的一部分。

  

noexcept-specification不是函数类型的一部分。 (直到   C ++ 17)

Source

因此,当推断出模板参数type时,noexcept不是推导类型的一部分。对于任何类型,您的编译器似乎都会返回true,这就是为什么您无法检测它是否为noexcept;这就是为什么一切都被接受的原因。

我遇到了同样的问题。你可以在这里查看我的问题/答案:

How can I detect whether a template argument is a noexcept function?

基本上,您唯一的选择是等待符合C ++ 17的编译器。