c++ - 我如何使用 SFINAE 确定非模板函数的优先级,同时还提供返回类型?

标签 c++ templates overloading

编辑:对之前的错误代码表示歉意。这是一个演示问题的可编译示例

我正在尝试实现一个简化为这种基本模式的访问者:

class Base {};

class BaseA : public Base {};
class BaseB : public Base {};

class DerivedA : public BaseA {
public:
    int operator+(DerivedA const& a) const
    {
        return 10;
    }
};

class DerivedB : public BaseB {
public:
    int operator+(DerivedB const& b) const
    {
        return 10;
    }
};

struct Adder
{
    int operator()(BaseA const& a, BaseB const& b)
    {
        std::cout << "Addition is not supported for these types.";
        return -1;
    }

    template <typename T, typename U>
    int operator()(T const& a, U const& b)
    {
        return a + b;
    }
};

int main()
{
    DerivedA a;
    DerivedB b;
    Adder adder;
    adder(a, a);
    adder(b, b);
    adder(a, b); // Compiler chooses templated function and fails if 
                 // operator+ is not supported.
}

如果基本类型匹配(我已将其设置为不支持 operator+ 的情况),我希望编译器选择非模板函数。然而,事实并非如此。

我相信我知道为什么(直接模板匹配比基类匹配好),以及Why is the compiler choosing this template function over an overloaded non-template function?的解决方案涉及替换失败不是错误 (SFINAE) 和 std::enable_if 似乎非常接近。

但是,该解决方案似乎只适用于返回 void 的函数。我如何调整 SFINAE 方法以允许我提供返回类型?

参见 http://ideone.com/uEbVmU对于编译错误:

Compilation error    time: 0 memory: 3296 signal:0
prog.cpp: In instantiation of ‘int Adder::operator()(const T&, const U&) [with T = DerivedA; U = DerivedB]’:
prog.cpp:48:15:   required from here
prog.cpp:37:22: error: no match for ‘operator+’ (operand types are ‘const DerivedA’ and ‘const DerivedB’)
             return a + b;
                      ^
prog.cpp:37:22: note: candidate is:
prog.cpp:12:13: note: int DerivedA::operator+(const DerivedA&) const
         int operator+(DerivedA const& a) const
             ^

最佳答案

以下更改自:

    template <typename T, typename U>
    int operator()(T const& a, U const& b)
    {
        return a + b;
    }

到:

    template <typename T, typename U>
    auto operator()(T const& a, U const& b) -> decltype(a+b)
    {
        return a + b;
    }

允许您的代码编译。原因是在选择使用哪个重载时,实例化函数模板的签名导致编译错误(添加a+b不匹配,因此decltype(a+b) 是一个错误)并且该函数从可能的重载集中删除。这使得非模板版本可用,并且每个人都赢了。

关于c++ - 我如何使用 SFINAE 确定非模板函数的优先级,同时还提供返回类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24185085/

相关文章:

c++ - C/C++中是否有称为 "hypochecking"的术语?

php - PHP 是否有一种与 Django 模板语言几乎相似的模板语言?

c++ - 我可以访问一般传递到模板中的结构吗?

c++ - 使用模板获取数组的大小和结束地址

java - 使用对象类的参数 vararg 和对象类的数组重载方法

c++ - 头文件和 cpp 文件中的运算符重载

c++模板函数用const参数覆盖参数推导

c++ - 尝试支持文字时构造函数重载歧义

c++ - 将编译器标志添加到 CMakeLists.txt

c++ - vtkSelectVisiblePoints 过滤器输出有 0 个点