C++构造函数SFINAE

4
#include <iostream>

using namespace std;

template <typename T>
class test {
public:
    T value;

    template <typename... Args, typename = decltype(T())>
    test(Args... args): value(args...)
    {
       cout <<"ctor running\n";
    }

    template <typename... Args>
    test(Args...) : value(1)
    {
       cout <<"ctor unspec  running\n";
    }
};


class t
{
public:
    t() = delete;
    explicit t(int) {}
};


int main()
{
    test<t> h;
}

我试图调用创建的对象(h)的第二个constructor。但是我不知道为什么会出现这个错误:

prog.cc: In function 'int main()':
prog.cc:45:13: error: call of overloaded 'test()' is ambiguous
     test<t> h;
             ^
prog.cc:25:5: note: candidate: 'test<T>::test(Args ...) [with Args = {}; T = t]'
     test(Args... args)
     ^~~~
prog.cc:19:5: note: candidate: 'test<T>::test(Args ...) [with Args = {}; <template-parameter-2-2> = t; T = t]'
     test(Args... args): value(args...)
     ^~~~

我试图将整个 class t 改为 private,但这也无法解决问题。我希望第二个 constructor 能够运行,即打印出

"ctor unspec running"

我在这里缺少什么?第一个 constructor 的调用应该被 SFINAed 掉,因为 typename = decltype(T()) 不起作用,因为 t 无法进行 default constructed 但是我得到了一个 ambiguous 的调用错误。

1个回答

5

SFINAE只发生在即时上下文中。由于T是类的模板参数而不是函数的模板参数,因此它不是即时上下文。这意味着它会成为一个“硬”错误。这是一个硬错误,因为无论您向constuctor的模板参数发送什么参数,它总是会出错。

解决方法是添加一个等于T的模板参数,并使用它来进行SFINAE:

template <typename... Args, typename U = T, typename = decltype(U{})>
test(Args... args): value(args...)
{
   cout <<"ctor running\n";
}

由于U是直接上下文,因此这里应用了SFINAE技术。

使用SFINAE技术时,没有任何排序。每个匹配函数都是“相等”的,这意味着如果有多个匹配函数,则没有更好的函数因为它是受限制的。因此,最好使用相反的约束条件来约束其他函数:

template <typename... Args, typename U = T,
    std::enable_if_t<!std::is_default_constructible<U>::value>* = nullptr>
test(Args...) : value(1)
{
   cout <<"ctor unspec  running\n";
}

现场示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接