Я использую 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
Проблема в выводе типа, сделанном конструкторами. Вы можете явно сделать типы, сделав класс шаблоном, а не его конструкторами. Это работает:
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));