3

我正在使用 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

4

1 回答 1

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));
于 2014-09-25T17:21:50.507 回答