【问题标题】:Workaround for VS2010: templates and overloaded functionsVS2010 的解决方法:模板和重载函数
【发布时间】:2012-09-21 08:21:29
【问题描述】:

我的代码是用 mingw/g++ 编译器完美构建的,但 MSVC (2010) 遇到错误。问题是重载的函数和模板。可能有人知道 MSVC 的解决方法吗?如果不存在解决方法(证明链接不可用),它也会回答。

代码示例:

#include <iostream>

struct Function 
{
    virtual ~Function() {}
    virtual void operator()() = 0;
};

template <typename Class, typename ARG1>
struct MemberFunction1 : public Function
{
    typedef void (Class::*MEM_FUNC)(ARG1);
    explicit MemberFunction1(Class * obj, MEM_FUNC func, ARG1 arg1) :  m_object(obj), m_func(func), m_arg1(arg1) {}

    virtual void operator()()
    {
        (m_object->*m_func)(m_arg1);
    }

    Class *  m_object;
    MEM_FUNC m_func;    
    ARG1     m_arg1;
};

struct FunctionStorage
{
    explicit FunctionStorage(Function * func) : m_func(func) {}

    virtual ~FunctionStorage()
    {
        if (m_func)
        {
            delete m_func;
            m_func = 0;
        }
    }

    void call() { (*m_func)(); }
    Function * m_func;
};

struct MemberFunction : public FunctionStorage
{
    template <typename Class, typename ARG1>
    MemberFunction(Class * obj, void (Class::*func)(ARG1), ARG1 arg1) : FunctionStorage(new MemberFunction1<Class, ARG1>(obj, func, arg1)) {}
};


class Foo 
{
public:
    void funcWithParam(int value)
    {
        std::cout << "foo::funcWithParam(" << value << ")\n";
    }
    void funcWithParam(const char * msg)
    {
        std::cout << "foo::funcWithParam(" << msg << ")\n";
    }
};

int main()
{
    Foo f;    
    MemberFunction(&f, &Foo::funcWithParam, 5).call(); // problem here, if remove one of funcWithParam (stay only 1 function, no overload) all will be ok
    MemberFunction(&f, &Foo::funcWithParam, "hello").call(); 
    return 0;
}

我的输出:

main.cpp(65): error C2660: 'MemberFunction::MemberFunction' : function does not take 3 arguments
main.cpp(65): error C2228: left of '.call' must have class/struct/union
main.cpp(66): error C2660: 'MemberFunction::MemberFunction' : function does not take 3 arguments
main.cpp(66): error C2228: left of '.call' must have class/struct/union

Here is ideone 构建结果。

【问题讨论】:

    标签: c++ templates visual-c++ overloading


    【解决方案1】:

    Foo::funcWithParam 的两个重载都匹配MemberFunction(Class * obj, void (Class::*func)(ARG1), ARG1 arg1) 中的void (Class::*func)(ARG1),因此第二个参数类型不明确:编译器无法确定 ARG1 是int 还是const char *

    有趣的是,如果您在模板化构造函数中颠倒参数的顺序,即如下所示: MemberFunction(Class * obj, ARG1 arg1, void (Class::*func)(ARG1) ) 并将您的呼叫站点更改为: MemberFunction(&amp;f, 5, &amp;Foo::funcWithParam) 它会起作用的。编译器首先遇到第二个参数,从中推断出类型 ARG1 是int。然后它继续处理第三个参数,因为它现在知道 ARG1 是 int,所以它知道要选择 &Foo::funcWithParam 的哪个重载。

    我不确定在这种情况下标准规定的行为应该是什么,但其中一个编译器肯定有一个错误,很可能是 VS2010。

    【讨论】:

    • 请注意,这并不完全正确。编译器应该尝试从所有个可能的地方推导出ARG1,并且只有当所有这些地方的推导都匹配时,才使用它。更改顺序不应影响模板参数推导。如果一个部分有歧义,而另一个部分有匹配,则使用匹配。
    • 好吧,我从来没有说过这种行为是正确的。我只是指出VS2010在这种情况下推断参数类型的方式有缺陷。
    • 我的意思是说这个解释并不完全正确,对不起。不是编译器取第一个推演匹配,而是尝试推演模板参数的所有出现。
    猜你喜欢
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 2014-04-20
    相关资源
    最近更新 更多