为什么这个构造函数重载不起作用? (模板和typedef发生)

时间:2014-07-11 08:26:43

标签: c++ templates visual-studio-2012 typedef constructor-overloading

我使用VS2012作为编译器。

由于缺少typedef

,首先有一个template aliasing
template <typename T>
struct HvVector
{
    typedef std::vector<T> rt;
};

然后我想实例化这个类的对象:

class LetYouDo
{
public:
    template<typename CLASS, typename TYPE>
    LetYouDo(const std::string& name, TYPE (CLASS::*field))
    {
        std::cout << "3" << std::endl;
    }

    template<typename CLASS, typename TYPE>
    LetYouDo(const std::string& name, typename HvVector<TYPE>::rt (CLASS::*field), TYPE* p)
    {
        std::cout << "4" << std::endl;
    }        
};

使用类似的示例类:

class Victim
{
public:
    int m1;
    HvVector<int>::rt m2;
};

所以真实案例如下:

Victim v;
v.m1 = 10;
v.m2.push_back(10);
LetYouDo o1("m1", &Victim::m1);
LetYouDo o2("m2", &Victim::m2, static_cast<int*>(0));

但编译器发出错误:

error C2660: 'LetYouDo::LetYouDo' : function does not take 3 arguments

所以看起来编译器不知道我的第二个构造函数,为什么?

额外的TYPE* p试图给编译器提供真实的类型,因为像typedef这样的HvVector<TYPE>::rt类型不能推断出模板参数类型,除非我明确指出它。

编辑:

这是一个适用于gcc 4.8.1的在线测试代码,所以我认为这是VS2012的问题:ideone.com/YawsaB

1 个答案:

答案 0 :(得分:0)

问题在于构造函数所做的类型推导。您可以通过使类成为模板而不是其构造函数来显式地创建类型。这有效:

template<typename CLASS, typename TYPE>
class LetYouDo
{
public:
    LetYouDo(const std::string& name, TYPE (CLASS::*field))
    {
        std::cout << "3" << std::endl;
    }

    LetYouDo(const std::string& name, typename HvVector<TYPE>::rt (CLASS::*field), TYPE* p)
    {
        std::cout << "4" << std::endl;
    }        
};

LetYouDo<Victim,int> o1("m1", &Victim::m1);
LetYouDo<Victim,int> o2("m2", &Victim::m2, static_cast<int*>(0));

如果将构造函数转换为方法,您将看到来自编译器的正确消息。尝试:

class LetYouDo
{

    template<typename CLASS, typename TYPE>
    void LetYouDoInit(const std::string& name, typename HvVector<TYPE>::rt (CLASS::*field), TYPE* p)
    {
        std::cout << "4" << std::endl;
    }        
};

LetYouDo o2;
o2.LetYouDoInit("m2", &Victim::m2, static_cast<int*>(0));

你会得到:

1>c:\users\all\documents\visual studio 2013\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp(47): error C2784: 'void LetYouDo::LetYouDoInit(const std::string &,HvVector<TYPE>::rt CLASS::* ,TYPE *)' : could not deduce template argument for 'HvVector<TYPE>::rt CLASS::* ' from 'std::vector<T,std::allocator<_Ty>> Victim::* '
1>          with
1>          [
1>              T=int
1>  ,            _Ty=int
1>          ]
1>          c:\users\all\documents\visual studio 2013\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp(24) : see declaration of 'LetYouDo::LetYouDoInit'
1>c:\users\all\documents\visual studio 2013\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp(47): error C2780: 'void LetYouDo::LetYouDoInit(const std::string &,TYPE CLASS::* )' : expects 2 arguments - 3 provided
1>          c:\users\all\documents\visual studio 2013\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp(18) : see declaration of 'LetYouDo::LetYouDoInit'

如果您明确说明类型,该消息将消失:

LetYouDo o2;
o2.LetYouDoInit<Victim,int>("m2", &Victim::m2, static_cast<int*>(0));