具有模板模板参数重载的C ++ 11/14友元运算符

时间:2017-01-11 20:20:21

标签: c++11 templates operator-overloading c++14 overload-resolution

在下面的代码中,我希望实现二进制运算符链接对我想要使用的特定类型定义的影响 - 对于简单的运算符链接,二元运算符返回相同类型的对象,大多数情况只是简单地返回*this,可以简单地再次用于链接相同类型的下一个对象。

但是,在我的情况下,二元运算符将两个相同类型对象(awaitable<T>::ref)的两个reference_wrappers作为输入,并返回类型为(awaitable<awaitable<T>::ref>)的聚合对象,我想使用返回的聚合对象链接下一个awaitable<T>::ref并再次返回类型awaitable<awaitable<T>::ref>的进一步聚合对象 - 注意返回的对象始终是awaitable<awaitable<T>::ref>的相同类型,无论多少链接发生了。

具有在位置(XXX)定义的模板模板参数的朋友操作员希望实现此目的,但编译器似乎不愿意执行绑定。

有人能说明如何实现所描述的结果吗?

谢谢!

#include <functional>

template <typename T>
struct awaitable
{
    typedef std::reference_wrapper<awaitable> ref;

    // (A) - okay
    friend awaitable<ref> operator||(ref a1, ref a2)
    {
        awaitable<ref> r;
        return r;
    }

    // (XXX) - this doesn't bind
    template < template <typename> class _awaitable >
    friend awaitable<ref> operator||(typename awaitable<typename _awaitable<T>::ref>::ref a1, ref a2)
    {
        awaitable<ref> r;
        return r;
    }
};

int main(int argc, const char * argv[])
{
    awaitable<void> a1;
    awaitable<void> a2;
    auto r1 = a1 || a2; // Okay - r1 is of type awaitable<awaitable<void>::ref>

    awaitable<void> a3;
    auto r3 = r1 || a3; // doesn't bind to the operator defined at XXX

    return 0;
}

[编辑] -

this帖子和this中的答案似乎很好地解释了这种情况,但在我的情况下,友元操作符有一个模板模板参数(需要避免递归模板实例化),可能会阻止编译器在实例化模板时生成正确的命名空间作用域函数吗?

2 个答案:

答案 0 :(得分:0)

这就是你需要的吗?

template < template <typename> class _awaitable, typename U >
friend auto operator||(_awaitable<std::reference_wrapper<U>> a1, ref a2)
{
    awaitable<ref> r;
    return r;
}

live demo

<强> EDIT1

我看到了你的答案,你删除了模板参数以使其正常工作。如果void是您使用的唯一类型,则效果很好。如果您尝试使用其他类型,它将失败。我最接近它的是使用std :: ref(r1)的表达。

template<typename U>
friend awaitable<ref> operator||(std::reference_wrapper<awaitable<std::reference_wrapper<awaitable<U>>>> a1, ref a2)
{
    std::cout << "(XXX2)" << std::endl;
    awaitable<ref> r;
    return r;
}

awaitable<int> a4;
auto r4 = std::ref(r1) || a4; 

live demo 2

答案 1 :(得分:0)

似乎带有模板模板参数的朋友功能使模板扣除失败。解决方案是删除模板模板参数,并在友元函数定义中将:: ref用法扩展为std :: reference_wrapper:

#include <functional>

template <typename T>
struct awaitable
{
    typedef std::reference_wrapper<awaitable> ref;

    // (A) - okay
    friend awaitable<ref> operator||(ref a1, ref a2)
    {
        awaitable<ref> r;
        return r;
    }

    // (XXX) - removing the template template parameter makes the template instantiation for a specific type T to generate a namespace version of the function!
    friend awaitable<ref> operator||(std::reference_wrapper<awaitable<std::reference_wrapper<awaitable<T>>>> a1, ref a2)
    {
        awaitable<ref> r;
        return r;
    }
};

// template <typename T>
// awaitable<typename awaitable<T>::ref> operator||(typename awaitable<typename awaitable<T>::ref>::ref a1, typename awaitable<T>::ref a2)
// {
//     awaitable<typename awaitable<T>::ref> r;
//     return r;
// }

int main(int argc, const char * argv[])
{
    awaitable<void> a1;
    awaitable<void> a2;
    auto r1 = a1 || a2; // Okay - r1 is of type awaitable<awaitable<void>::ref>

    awaitable<void> a3;
    auto r3 = r1 || a3; // now it works!

    return 0;
}

演示here