首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与SFINAE检查

与SFINAE检查
EN

Stack Overflow用户
提问于 2018-10-11 06:36:30
回答 2查看 119关注 0票数 2

我在尝试使用sfinae检查做朋友声明时遇到了一些麻烦(如果您不需要解释“为什么”和“如何”,就可以跳进代码示例)。

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

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

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

我理解为什么评论中的内容失败(或者我认为我会),但我不知道如何解决它。

代码语言:javascript
复制
#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
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-10-11 07:26:58

如果您放弃了不同的名称f1f2,转而执行标记分派,则整个方案可以大大简化(也可以耦合):

代码语言:javascript
复制
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提醒我)。由于该标记位于继承链中,因此可以为这两个重载提供第二个参数priority<1>{},但如果两者都可行,则将有利于更接近的匹配。

票数 3
EN

Stack Overflow用户

发布于 2018-10-11 06:56:22

在模板化类中处理模板友人函数的一个常见的简单解决方案是将模板本身声明为朋友,而不是仅仅声明当前实例化所特有的重载:

代码语言:javascript
复制
template<class T>
class A
{
    ...

    template<typename U>
    friend auto sfinae_check(U &u, A<U> &a, int) -> decltype(u.b1(), void()); 

    template<typename U>
    friend auto sfinae_check(U &u, A<U> &a, long) -> decltype(u.b2(), void()); 

    ...
};

这似乎解决了你的问题:https://gcc.godbolt.org/z/8UGGZM

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52753733

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档