Templates 运算符重载的模板化定义

Templates 运算符重载的模板化定义,templates,c++11,sfinae,Templates,C++11,Sfinae,我有一些函数对象,每个对象都定义运算符()的各种双参数重载: 现在我要做的是编写一个实用程序,让我把这些函子一个接一个地附加到一个二进制运算符上。以下是我的尝试: #define ATTACH_FUNCTOR_TO_OPERATOR(OPERATOR, FUNCTOR) \ template<typename Operand1, typename Operand2> \ decltype(FUNCTOR(std::declval<Operand1>(),

我有一些函数对象,每个对象都定义运算符()的各种双参数重载:

现在我要做的是编写一个实用程序,让我把这些函子一个接一个地附加到一个二进制运算符上。以下是我的尝试:

#define ATTACH_FUNCTOR_TO_OPERATOR(OPERATOR, FUNCTOR) \
    template<typename Operand1, typename Operand2> \
    decltype(FUNCTOR(std::declval<Operand1>(), std::declval<Operand2>())) \
    operator OPERATOR(const Operand1 &operand1, const Operand2 &operand2) { \
        return FUNCTOR(operand1, operand2); \
    }
但当我用同一个操作符添加第二个调用时:

class Foo {};
class Bar {};

struct Functor1 {
    double operator()(const Foo &, const Bar &)  { return 2.2; }
    double operator()(const Bar &, const Foo &)  { return 3.1; }
};

struct Functor2 {
    int operator()(const Foo &, const Foo &)  { return 2; }
    int operator()(const Bar &, const Bar &)  { return 3; }
};
ATTACH_FUNCTOR_TO_OPERATOR(+, Functor2());
然后Visual Studio 2013告诉我“函数模板已经定义”

请注意,对于任何一对操作数,只有一个+实例的返回类型
decltype(FUNCTOR(std::declval(),std::declval())
可以解析为任何特定类型。我期望任何其他尝试的实例化都会无声地失败,不会引起任何问题——也就是SFINAE

我还尝试了各种风格的
enable_if
,但没有成功

在标准C++11中是否有合法的方法来实现这一点


有一种方法可以在VS2013中使用吗?

下面的简化示例在ideone中编译得很好,并返回正确的结果,因此我只能想象它是某种VS2013错误。但是我不是C++标准专家,所以我不知道是否需要编译器来处理这个场景

#include <iostream>
#include <type_traits>
using namespace std;

class Foo {};
class Bar {};

struct Functor1
{
    static double functor(const Foo &) { return 2.2; }
};

struct Functor2
{
    static int functor(const Bar &) { return 3; }
};

template<typename Operand>
auto test(const Operand &operand) -> decltype(Functor1::functor(operand))
{
    return Functor1::functor(operand);
}

template<typename Operand>
auto test(const Operand &operand) -> decltype(Functor2::functor(operand))
{
    return Functor2::functor(operand);
}

int main()
{
    cout << test(Foo()) << endl << test(Bar());
    return 0;
}
#包括
#包括
使用名称空间std;
类Foo{};
类条{};
结构函子1
{
静态双函子(constfoo&{return2.2;}
};
结构函子2
{
静态int函子(常数条&){return 3;}
};
模板
自动测试(常量操作数和操作数)->decltype(Functor1::functor(操作数))
{
返回Functor1::functor(操作数);
}
模板
自动测试(常量操作数和操作数)->decltype(Functor2::functor(操作数))
{
返回Functor2::functor(操作数);
}
int main()
{
cout这是VC++中的一个示例。我们可以将其简化为以下自包含示例:

template<typename T> void f(decltype(T::a)) {}
template<typename T> void f(decltype(T::b)) {}

也许我错了,但它不应该是
将\u FUNCTOR\u附加到\u运算符(+,FUNCTOR 1)
(不带括号)?没关系,我误读了代码。可能是编译器错误。。啊,我曾考虑使用标记分派来消除歧义,但出于某种原因,我认为它无法与OPs代码中的运算符一起工作。解决方法很好,错误:)再次,正如您指向Microsoft connect的链接所显示的,Microsoft似乎忽略了这个问题。感谢您的回答。它如前所述解决了问题,但在我尝试正常使用运算符的站点,即它与我自己的任何重载都不匹配的站点,它会导致失败。我将致力于构建一些干净的示例代码。更新:一切都很好。我只需要非常接近您编写的内容。(我在宏的第一行将结果类型定义为默认的第三个模板参数,并在第2行使用该模板参数作为返回类型;我在第2行添加了std::conditional maneouvre。这还不够接近。)
template<typename T> void f(decltype(T::a)) {}
template<typename T> void f(decltype(T::b)) {}
#define ATTACH_FUNCTOR_TO_OPERATOR(OPERATOR, FUNCTOR) \
    template<typename Operand1, typename Operand2> \
    typename std::conditional<true, \
        decltype(FUNCTOR(std::declval<Operand1>(), std::declval<Operand2>())), \
        std::integral_constant<int, __LINE__>>::type \
    operator OPERATOR(const Operand1 & operand1, const Operand2 &operand2) { \
        return FUNCTOR(operand1, operand2); \
    }