【问题标题】:Why doesn't SFINAE appear to work with nullptr overload here?为什么 SFINAE 在这里似乎不适用于 nullptr 重载?
【发布时间】:2016-04-12 14:25:02
【问题描述】:

我试图从一个没有int 构造函数但从nullptr 构造的类派生,试图使派生的构造函数在采用单个参数时尽可能通用。但由于某种原因,似乎没有采用正确的构造函数,即使将 int 替换为模板构造函数会导致失败:

#include <cstddef>
#include <iostream>

struct Base
{
    Base(std::nullptr_t){}
    Base(){}
    // some other constructors, but not from int
};

struct Test : Base
{
    Test(std::nullptr_t) : Base(nullptr)
    {
        std::cerr << "Test(nullptr)\n";
    }
    template<typename T>
    Test(T v) : Base(v) {}
};

int main()
{
    Base b=0;       // works
    Test z=nullptr; // works
    Test t=0;       // compilation error
}

为什么会这样?这不是 SFINAE 的意思吗?我该如何解决这个问题?

【问题讨论】:

  • 使用template&lt;typename T, typename = decltype(Base(std::declval&lt;T&amp;&gt;()))&gt; 获得 SFINAE 效果
  • 这里不涉及 SFINAE。
  • 长话短说:0 需要转换才能成为nullptr,因此首选模板。
  • 您的代码示例所指的编译错误是什么?
  • 尤其是nullptr_t n = 0;的部分

标签: c++ sfinae


【解决方案1】:

成员初始化列表不是所谓的“立即上下文”的一部分。 SFINAE 仅保护此直接上下文。

此外,SFINAE 仅保护不属于函数体的函数声明部分(定义部分)的替换。成员初始化列表属于构造函数体。这个主体是独立于声明实例化的,这里的任何错误都是致命的。

【讨论】:

    【解决方案2】:

    GCC 告诉我

    36576202.cpp: In instantiation of ‘Test::Test(T) [with T = int]’:
    36576202.cpp:25:12:   required from here
    36576202.cpp:18:23: error: no matching function for call to ‘Base::Base(int&)’
         Test(T v) : Base(v) {}
                           ^
    36576202.cpp:18:23: note: candidates are:
    36576202.cpp:7:5: note: Base::Base()
         Base(){}
         ^
    36576202.cpp:7:5: note:   candidate expects 0 arguments, 1 provided
    36576202.cpp:6:5: note: Base::Base(std::nullptr_t)
         Base(std::nullptr_t){}
         ^
    36576202.cpp:6:5: note:   no known conversion for argument 1 from ‘int’ to ‘std::nullptr_t’
    36576202.cpp:4:8: note: constexpr Base::Base(const Base&)
     struct Base
            ^
    36576202.cpp:4:8: note:   no known conversion for argument 1 from ‘int’ to ‘const Base&’
    36576202.cpp:4:8: note: constexpr Base::Base(Base&&)
    36576202.cpp:4:8: note:   no known conversion for argument 1 from ‘int’ to ‘Base&&’
    

    这表明

    • Test t=0; 通过模板 Test(T)T==int。这是一个有效的替换,因此 SFINAE 不相关。
    • Test(T==int) 然后需要Base(int),它不存在。并且没有从intnullptr_t 的转换。

    【讨论】:

      猜你喜欢
      • 2017-04-24
      • 1970-01-01
      • 2011-02-03
      • 2010-12-23
      • 1970-01-01
      • 1970-01-01
      • 2017-06-13
      • 2011-09-27
      • 1970-01-01
      相关资源
      最近更新 更多