Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否可以创建一个包含三种数据类型之一的容器,并且可以通过单个接口进行查询?_C++_Boost - Fatal编程技术网

C++ 是否可以创建一个包含三种数据类型之一的容器,并且可以通过单个接口进行查询?

C++ 是否可以创建一个包含三种数据类型之一的容器,并且可以通过单个接口进行查询?,c++,boost,C++,Boost,我有一个容器对象,它包含int、float或string。我有一个以类似方式处理的容器队列。目前,对于不同的数据类型,我有不同的getter。考虑到每个容器实例一次只包含一种数据类型,这并不是特别优雅 class MyContainer { MyContainer(float value); MyContainer(int value); MyContainer(string value); int getIntValue(); float getFlo

我有一个容器对象,它包含int、float或string。我有一个以类似方式处理的容器队列。目前,对于不同的数据类型,我有不同的getter。考虑到每个容器实例一次只包含一种数据类型,这并不是特别优雅

class MyContainer
{
    MyContainer(float value);
    MyContainer(int value);
    MyContainer(string value);

    int getIntValue();
    float getFloatValue();
    string getStringValue();
}

void processContainer(MyContainer& container)
{
    // the following will not work, but is desired:
    process(container->getValue()); // compilation error
}

void process(int value) {}
void process(float value) {}
void process(string value) {}

有没有一种方法可以利用上面的process方法的参数重载?例如,通过某种方式,我可以简单地调用process(container->getValue())?

您可以使用模板和traits将模板化代码限制为string、float、int类型。如果您提前知道每个值的类型,那么A
union
可能会起作用。如果您可以使用Qt库,则是一个选项。

问题在于知道应该由
processContainer
MyContainer
中选择哪个值。由于这些知识被封装在MyContainer中,因此流程调用可能也应该如此,或者至少是对它的分派。即:

class MyContainer
{
    MyContainer(float value);
    MyContainer(int value);
    MyContainer(string value);

    invokeProcess()
    {
       // call correct overload of process based on value stored
    }

    int getIntValue();
    float getFloatValue();
    string getStringValue();
}

void processContainer(MyContainer& container)
{
    container->invokeProcess(); 
}
您还可以使用多态性和MyContainer的几个子类来实现这一点。基本上,您可以将转换逻辑从invokeProcess内部的case语句转换为外部的虚拟函数查找


其他人提到了工会。您确实需要一个有区别的并集,包括一个枚举来知道值是什么类型。

不幸的是,可能不是,至少不是以任何优雅的方式。C++不允许只在返回类型上不同的重载函数,所以每个数据类型都必须有一个吸气剂。您可以有三个名为相同的函数,它们接受您想要返回的类型的伪变量,或者以指针作为参数并以这种方式返回值,但是如果我正确理解您的目的,那么这两个选项都不能使您更接近
进程(container->getValue())

,您想让MyContainer保存int、float或string

在这种情况下,您肯定需要模板来定义类:

template<typename T>
class MyContainer 
{
private:
    T _value;

    MyContainer(T value)
    {
        _value = value;
    }

public:
    T GetValue()
    {
        return _value;
    }
}

另一种方法是使用
Visitor
模式。这允许您根据类型动态地进行分派

struct Float;
struct Integer;

struct ContainerVisitor {
    virtual void visit(Float& value) = 0;
    virtual void visit(Integer& value) = 0;
    // etc.
};

struct Container {
    virtual void accept(ContainerVisitor& visitor) = 0;
};

struct Integer : Container{
    virtual void accept(ContainerVisitor& visitor) {
        visitor.visit(*this);
    }
};

struct Float : Container{
    virtual void accept(ContainerVisitor& visitor) {
        visitor.visit(*this);
    }
};
然后,无论您希望执行什么操作,都将其放入从
ContainerVisitor
派生的类中:

struct Processor : ContainerVisitor {
    virtual void visit(Float& value) {
        // equivalent of your process(float);
    }
    virtual void visit(Integer& value) {
        // equivalent of your process(int);
    }
};
用法如下:

int main() {
    Processor processor;

    Integer i;
    Float f;

    i.accept(processor);
    f.accept(processor);
}

假设每个容器实例一次只保存一种数据类型
:使用union如何?如果每个容器只保存一种数据类型,为什么不将容器作为模板?std::string不能包含在union中。我可以封装整数和浮点,但这并不能解决我的问题(只会节省我一个字节)。我想知道,
process
为什么不是
MyContainer
的成员?
boost::variant
!这是一个已解决的问题。现在没有时间正确回答,但您正在搜索的是
静态访问者
。这是一个非常好且优雅的解决方案
struct Processor : ContainerVisitor {
    virtual void visit(Float& value) {
        // equivalent of your process(float);
    }
    virtual void visit(Integer& value) {
        // equivalent of your process(int);
    }
};
int main() {
    Processor processor;

    Integer i;
    Float f;

    i.accept(processor);
    f.accept(processor);
}