首页 > 解决方案 > 编译时选择特定方法,伪装成操作符

问题描述

我有一堂像这样的课:

struct Base
{
    void aa(int n) const {
        std::cout << "aa() " << field*n << std::endl;
    }

    void bb(int n) const {
        std::cout << "bb() " << field*n*2 << std::endl;
    }

    int field = 2;
};

我希望能够在编译时选择两个实现之一,aa()或者bb()通过调用运算符方法。就像是:

Base data;
Magic obj(data);
obj.as_AA() * 33; // should call data.aa(33)
obj.as_BB() * 44; // should call data.bb(44)

data不得重复。而aa()vs的选择bb()必须在编译时解决。

我有一个使用向下转换的解决方案,其行为在理论上是未定义的(我认为)。它构建(使用 g++ 和 clang++)并完美运行,但仍然......

struct AA : public Base
{
    void operator*(int n) const {
        return Base::aa(n);
    }
};

struct BB : public Base
{
    void operator*(int n) const {
        return Base::bb(n);
    }
};

struct Chooser
{
    Base obj;

    template<typename WHICH> // will be either AA or BB
    const WHICH& as() const {
        return static_cast<const WHICH&>( obj ); // downcasting
    }
};

main.cpp

Chooser ch;
ch.as<AA>() * 5; // prints "aa() 10"
ch.as<BB>() * 7; // prints "bb() 28"

我的解决方案有多不可靠?(因为技术上未定义的向下转换)

你看到替代品了吗?

谢谢


ps:当然我可以简单地使用

Base data;
data.aa(33);
data.bb(44);

但我真的想通过相同的名称访问不同的实现,即 operator*


我也可以使用模板化的 operator* inBase并具有显式的模板特化,但这会迫使我使用丑陋的语法,这会使运算符的用途无效:

struct Base {
    \\...
    template<int N> void operator*(int n) const;
};

template<> void Base::operator*<1>(int n) const {
    aa(n);
}

这需要:

Base data;
data.operator*<1>(44); // ugly

标签: c++templatesoperator-overloadingdowncast

解决方案


你可以这样写Magic类:

struct Magic  {
   
    Magic(Base &b) : b(b) {}
    
    Base &b;
     
    struct AA {
        Base &b;
        void operator*(int n) const {
        return b.aa(n);
     }
    };
    
    struct BB {
        Base &b;
        void operator*(int n) const {
        return b.bb(n);
     }
    };
    
    AA as_AA() { return AA{b}; }
    
    BB as_BB() { return BB{b}; }
};

这通过使用组合来避免任何继承。此外,没有data对象的副本,因为仅对其进行了引用。

现在您可以准确地使用您想要的调用语法,并且它具有正确的行为:

Base data;
Magic obj(data);
obj.as_AA() * 33; // calls data.aa(33) -- prints 66
obj.as_BB() * 44; // calls data.bb(44) -- prints 176

这是一个演示


推荐阅读