为什么C ++更喜欢这种模板方法的方法重载?

时间:2012-06-07 12:24:36

标签: c++ templates boost overloading

假设我有两个类,第一个用于编写基本类型(boolintfloat等),第二个用于扩展第一个类以编写复杂类型:

struct Writer {
    virtual void Write(int value) = 0;
};

struct ComplexWriter : public Writer {
    template <typename TValue> void Write(const TValue &value) {
        boost::any any(value);
        Write(any);
    }
    //virtual void Write(int value) = 0; // see question below
    virtual void Write(const boost::any &any) = 0;
};

这个想法是,如果有人调用myWriter.Write(someIntValue);,则int重载将优先于模板化方法。

相反,我的编译器(Visual C ++ 11.0 RC)总是选择模板方法。例如,以下代码段将Wrote any打印到控制台:

struct ComplexWriterImpl : public ComplexWriter {
    virtual void Write(int value) { std::cout << "Wrote an int"; }
    virtual void Write(const boost::any &any) { std::cout << "Wrote any"; }
};

void TestWriter(ComplexWriter &writer) {
    int x = 0;
    writer.Write(x);
}

int main() {
    ComplexWriterImpl writer;
    TestWriter(writer);
}

当我在Write(int)类中声明ComplexWriter方法时,行为会突然改变(请参阅第一个代码段中的注释掉的行)。然后它将Wrote an int打印到控制台。

这是我的编译器应该如何表现的吗? C ++标准是否明确规定只有在同一个类(而不是基类)中定义的重载才能优先于模板化方法?

2 个答案:

答案 0 :(得分:7)

问题是,在您调用writer.Write(x)时,编译器会看到ComplexWriter而不是ComplexWriterImpl,因此它只知道{{1}中定义的函数} - 模板函数和ComplexWriter函数。

boost::any不包含任何接受ComplexWriter的虚函数,因此无法调用int中定义的int重载

当您将虚拟重载添加到ComplexWriterImpl类时,编译器会发现ComplexWriter类中存在整数重载,因此在ComplexWriter中调用它的实现}

编辑:现在你已经编辑了ComplexWriter和amp;之间的继承。作家,我有一个更完整的解释:

当你创建一个子类并在其中定义一个函数时,无论它们的参数类型如何,基类中该名称的所有函数都将被隐藏。

你可以使用我认为的using关键字解决这个问题:

ComplexWriterImpl

有关详细信息,请参阅此常见问题解答条目:http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

编辑2:只是为了确认这确实解决了您的问题:http://ideone.com/LRb5a

答案 1 :(得分:2)

当您通过ComplexWriter“interface”访问该对象时,编译器将尝试使用该类中的定义解析对Write(int)的函数调用。如果它不能这样做,它将考虑基类。

在这种情况下,您有两个候选人:Write(any)和模板化版本。由于此时没有明确的Write(int),因此必须在这两个选项之间进行选择。 Write(any)需要隐式转换,而模板化版本则不需要,因此调用模板化版本(反过来调用Write(any))。

要使Write(int)的{​​{1}}可用,请导入Writer个功能:

Writer::Write