c++ - SFINAE 错误

标签 c++ c++11 c++14 template-meta-programming sfinae

为什么下面的代码会出错?我认为编译器只是在这里选择适当的重载?

#include <iostream>
using std::cout;
using std::endl;

template <typename ToCheckFor>
struct InterfaceCheck {

    // used by the constexpr function, the function will pass in a pointer to
    // a type with the required types
    template <typename _ToCheckFor, void (_ToCheckFor::*) ()>
    struct InterfaceCheckImplTag {};

    // used to check for the presence of a function print()
    // template <typename T>
    // static constexpr bool function(__attribute__((unused)) void* ptr) {}
    template <typename T>
    static constexpr bool function(__attribute__((unused)) void* ptr) { 
        return false; 
    }
    template <typename T>
    static constexpr bool function (__attribute__((unused))  
         InterfaceCheckImplTag<T, &T::print>* ptr) { 

        return true; 
    }

    constexpr static const bool value = function<ToCheckFor>(nullptr);
};

struct Something {
    void print() { cout << "Something::print()" << endl; }
};

int main() {

    cout << InterfaceCheck<Something>::value << endl;

    return 0;
}

为什么用省略号替换 void* 参数会使代码按预期工作?所以下面的代码可以按预期工作

#include <iostream>
using std::cout;
using std::endl;

template <typename ToCheckFor>
struct InterfaceCheck {

    // used by the constexpr function, the function will pass in a pointer to
    // a type with the required types
    template <typename _ToCheckFor, void (_ToCheckFor::*) ()>
    struct InterfaceCheckImplTag {};

    // used to check for the presence of a function print()
    // template <typename T>
    // static constexpr bool function(__attribute__((unused)) void* ptr) {}
    template <typename T>
    static constexpr bool function(...) { 
        return false; 
    }
    template <typename T>
    static constexpr bool function (__attribute__((unused))  
         InterfaceCheckImplTag<T, &T::print>* ptr) { 

        return true; 
    }

    constexpr static const bool value = function<ToCheckFor>(nullptr);
};

struct Something {
    void print() { cout << "Something::print()" << endl; }
};

int main() {

    cout << InterfaceCheck<Something>::value << endl;

    return 0;
}

最佳答案

Why does the following code cause an error?

函数重载有两种可行的选择。两者都涉及从提供的参数进行转换,并且两种转换都不比另一种转换更好:

error: call to 'function' is ambiguous
    constexpr static const bool value = function<ToCheckFor>(nullptr);
                                        ^~~~~~~~~~~~~~~~~~~~
test.cpp:36:13: note: in instantiation of template class 'InterfaceCheck<Something>' requested here
    cout << InterfaceCheck<Something>::value << endl;
            ^
test.cpp:17:27: note: candidate function [with T = Something]
    static constexpr bool function(__attribute__((unused)) void* ptr) { 
                          ^
test.cpp:21:27: note: candidate function [with T = Something]
    static constexpr bool function (__attribute__((unused))  

使用 function(...) 进行修复是有效的,因为从任何内容到 ... 的转换始终比其他任何内容都“更差”匹配(但仍然合法) 。一旦你了解了它,这就是一个很棒的技巧。

来自 13.3.3.2 排名隐式转换序列 [over.ics.rank]:

  1. When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1)

    • a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and

    • a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence (13.3.3.1.3).

历史

我第一次学到这个技术是从Modern C++ Design ,第 2.7 节。我不确定这是否是它的发明地。但这并不是一个糟糕的猜测。这本书现在已经 15 年了,仍然值得一读。

关于c++ - SFINAE 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36268560/

相关文章:

C++设计题

c++ - 为匿名身份验证配置 mongoose

c++ - 在 OS X 上轮询和选择奇怪的行为

c++ - 多个枚举值的一个模板特化

c++ - 调整捕获的 lambda 值

c++ - Mac OSX 已弃用的 API - FSRef 引用;

c++ - MFC 打开文件位置并选择(突出显示)文件

c++11 原子排序 : extended total order memory_order_seq_cst for locks

c++ - 在元组中搜索函数的参数

c++ - C++中元组元素类型的大小总和