ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 与SFINAE支票交朋友

2019-08-28 00:06:51  阅读:178  来源: 互联网

标签:friend-function c templates friend sfinae


我试图用sfinae检查进行朋友声明时遇到了一些麻烦(如果你不想解释“为什么”和“如何”,你可以跳进代码示例).

基本上,我有一些模板类声明两个私有成员函数.根据模板类型的实例化,我想使用一个或另一个函数.

因此,如果我不希望编译失败,则无法实例化我无法使用的私有函数.所以,我必须通过sfinae检查(一个独立的功能)来调用它.考虑到它是私人的,我必须让我的sfinae检查我班上的朋友.

但是,我无法做到这一点,正如下面的(最小)代码所示.我不想改变的事情:A类的原型(f1和f2必须保持私有),B1和B2类的原型.

我理解为什么评论中的内容失败(或者我认为我这样做),但我不知道如何修复它.

#include <iostream>

template<class T> class A;

template<class T>
auto sfinae_check(T& t, A<T>& a, int)  -> decltype(t.b1(), void());

template<class T>
auto sfinae_check(T& t, A<T>& a, long)  -> decltype(t.b2(), void());

template<class T>
class A
{
    void f1() { t.b1(); }
    void f2() { t.b2(); }

    T& t;

    //friend auto sfinae_check<>(T &t, A<T> &a, int);//obviously mismatches everything
    //friend auto sfinae_check<>(T &t, A<T> &a, int) -> decltype(t.b1(), void()); //failure : no member named b1
    //friend auto sfinae_check<>(T &t, A<T> &a, long) -> decltype(t.b2(), void()); //failure : no member named b2

    public:
        A(T& t) : t(t) {}
        void f() { sfinae_check(t, *this, 0); }
};

template<class T>
auto sfinae_check(T& t, A<T>& a, int)  -> decltype(t.b1(), void())
{
    a.f1();
}

template<class T>
auto sfinae_check(T& t, A<T>& a, long)  -> decltype(t.b2(), void())
{
    a.f2();
}

struct B1
{
    void b1() { std::cout << "b1" << std::endl; }
};

struct B2
{
    void b2() { std::cout << "b2" << std::endl; }
};

int main()
{
    B1 b1; B2 b2;

    A<B1> a1(b1);
    a1.f(); //should print b1

    A<B2> a2(b2);
    a2.f(); //should print b2
}

解决方法:

如果您放弃不同的名称f1和f2并执行标记调度,则整个方案可以简化很多(在耦合中):

template<int> struct tag{};

template<int i> struct priority : priority<i - 1> {};
template<> struct priority <0>{};

template<class T>
auto sfinae_check(T& t, priority<1>)  -> decltype(t.b1(), tag<1>{}) { return {}; }

template<class T>
auto sfinae_check(T& t, priority<0>)  -> decltype(t.b2(), tag<0>{}) { return {}; }

template<class T>
class A
{
    void f(tag<1>) { t.b1(); }
    void f(tag<0>) { t.b2(); }

    T& t;

    public:
        A(T& t) : t(t) {}
        void f() { f(sfinae_check(t, priority<1>{})); }
};

没有友谊,几乎没有循环依赖,你看到你想要的确切输出.并且如果需要的话,作为最重要的结果,添加对另一个重载的支持应该相当容易.

重载的优先级也在这里编码(感谢Jarod42提醒我).由于该标签位于继承链中,因此可以将第二个参数优先级< 1> {}提供给任一重载,但是如果两者都可行,则它将有利于更接近的匹配.

标签:friend-function,c,templates,friend,sfinae
来源: https://codeday.me/bug/20190827/1746066.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有