2

前言

下面有一个 SSCCE 链接。

我已经定义了一个模板类,它在我的程序中声明了一个嵌套类。std::ostream::operator <<该模板适用于许多不同的数据类型(即被std::ostream::operator <<.

所以这是基本界面:

class Value;

class Datatype {

public:

    virtual std::string to_string(Value* value) = 0;

};

class Value {

    Datatype* m_type;

public:

    Value(Datatype* type) : m_type(type) { }

    std::string to_string() {
        return m_type->to_string(this);
    }

};

模板类的WrapValueImpl作用(见下文)是将一个ValueDatatype实现合二为一。

template <typename T>
class WrapValueImpl : public Value {

    T m_val;

public:

    WrapValueImpl(Datatype* type) : Value(type) { }

    T& get() {
        return m_val;
    }

    static T& get(Value* value) {
        return static_cast<WrapValueImpl*>(value)->get();
    }

    static void set(Value* value, const T& other) {
        get(value) = other;
    }

    class Type : public ::Datatype {

    public:

        virtual std::string to_string(Value* value) {
            std::ostringstream stream;
            stream << WrapValueImpl::get(value);
            return stream.str();
        }

    };

};

示例用法:

typedef WrapValueImpl<int> IntValue;

int main() {
    IntValue::Type t;
    IntValue v(&t);
    IntValue::set(&v, 42);

    std::cout << v.to_string() << "\n"; // prints 42
    return 0;
}

到目前为止一切顺利,这正是我想要的。

问题

但是现在,我想WrapValueImpl使用std::ostream::operator <<. 请再次注意,我不想添加对<<运营商的支持。

更确切地说,我想覆盖 中的TypeWrapValueImpl以实现正确的字符串转换。

typedef std::vector<Value*> ValueArray;
class ArrayValue : public WrapValueImpl<ValueArray> {

public:

    ArrayValue(Datatype* type) : WrapValueImpl<ValueArray>(type) { }

    class Type : public WrapValueImpl<ValueArray>::Type {

    public:

        virtual std::string to_string(Value* value) {
            std::ostringstream stream;
            stream << "[";

            ValueArray& array = ArrayValue::get(value);
            ValueArray::const_iterator it = array.begin();
            for (; it != array.end(); it++) {
                stream << (*it)->to_string() << ", ";   
            }
            stream << "]";
            return stream.str();
        }

    };

};

但它根本不编译。编译器会产生错误,就好像我使用的是原始WrapValueImpl<ValueArray>::Type类而不是ArrayValue::Type类一样。但是,我确实进行了测试并插入了打印件,Type::to_string()并调用了正确的方法(被覆盖类的方法)。

(SSCCE)但它实际上使用了正确的Type类......

在以下关于 Coliru 的片段中,您可以找到我正在谈论的完整工作示例。您可以切换USE_ARRAY宏来查看使用ArrayValue类的结果。

http://coliru.stacked-crooked.com/a/820e2f2550a8363e

在这个例子中,我还证明了编译器实际上选择了正确的嵌套类型类,但它抱怨原始实现。为什么它实际上不使用 type时会打扰?

4

1 回答 1

0

问题是,当您像这样定义Type时,编译器将从 impl 中实例化。在模板类型 T 上使用 operator << 中定义,因为他没有 operator << for T 它会抛出错误。ArrayValuepublic WrapValueImpl<ValueArray>::TypeTypeWrapValueImplTypeWrapValueImpl

解决此问题的一种方法是为您的值类型使用运算符:

std::ostringstream& operator << (std::ostringstream& stream,const ValueArray & va);

class ArrayValue : public WrapValueImpl<ValueArray> {

public:

    ArrayValue(Datatype* type) : WrapValueImpl<ValueArray>(type) { }

};

std::ostringstream& operator << (std::ostringstream& stream,const ValueArray & array)
{
    stream << "[";

    ValueArray::const_iterator it = array.begin();
    for (; it != array.end(); it++) {
        stream << (*it)->to_string() << ", ";   
    }
    stream << "]";
    return stream;
};

只是不要Type在你的ArrayValue班级中定义。

于 2013-11-04T16:52:02.620 回答