前言
下面有一个 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
模板类确实(见下文),是传递一个Value
和 Datatype
一站式实现。
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 <<
中不受支持.请再次注意,我不想添加对 <<
的支持。运营商。
更确切地说,我想覆盖 Type
WrapValueImpl
中的类实现正确的字符串转换。
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
类(class)。然而,我确实进行了测试并在 Type::to_string()
中插入了打印件。并调用正确的方法(被覆盖类的方法)。
(SSCCE) 但它实际上使用了正确的 Type
类...
在 Coliru 上的以下片段中,您可以找到我正在谈论的内容的完整工作示例。您可以切换 USE_ARRAY
宏查看使用 ArrayValue
的结果类。
http://coliru.stacked-crooked.com/a/820e2f2550a8363e
在这个例子中,我还证明了编译器实际上选择了正确的嵌套类型类,但它提示原始实现。当它实际上不使用该类型时,为什么会麻烦?
最佳答案
问题是当你定义Type
在ArrayValue
像这样public WrapValueImpl<ValueArray>::Type
然后编译器将实例化 Type
来自 WrapValueImpl
暗示。 Type
在 WrapValueImpl
中定义在模板化类型 T 上使用运算符 <<,因为 T 没有运算符 <<,所以会抛出错误。
解决此问题的一种方法是为您的值类型使用运算符:
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
类。
关于C++ 覆盖嵌套类只能部分说服编译器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19772163/