我有一个成功编译的代码(g ++ 4.9.2):
#include <iostream>
#include <utility>
// general function for any variadic templated argument
template<template<typename ...> class T, typename ...TTs>
void
foo(T<TTs...>& arg)
{
std::cout << "T<TTs...>" << std::endl;
}
template<typename ...Ts>
struct xxx
{
// not important
};
// specialization for only variadic templated xxx
template<typename ...TTs> void
foo(xxx<TTs...>& arg)
{
std::cout << "xxx<TTs...>" << std::endl;
}
// specialization for non-variadic templated xxx
template<typename TT> void
foo(xxx<TT>& arg)
{
std::cout << "xxx<TT>" << std::endl;
}
// specialization for xxx<uint8_t>
template<> void
foo(xxx<uint8_t>& arg)
{
std::cout << "xxx<uint8_t>" << std::endl;
}
int
main(int argc, char** argv)
{
xxx<uint8_t> x1;
std::cout << "xxx<uint8_t> => ";
foo(x1);
xxx<uint16_t> x2;
std::cout << "xxx<uint16_t> => ";
foo(x2);
xxx<uint8_t,uint16_t> x3;
std::cout << "xxx<uint8_t,uint16_t> => ";
foo(x3);
std::pair<uint8_t,uint16_t> x4;
std::cout << "std::pair<uint8_t,uint16_t> => ";
foo(x4);
return 0;
}
并产生:
xxx<uint8_t> => xxx<uint8_t>
xxx<uint16_t> => xxx<TT>
xxx<uint8_t,uint16_t> => xxx<TTs...>
std::pair<uint8_t,uint16_t> => T<TTs...>
现在我想在一个类中使用这些foo方法,并编写:
#include <iostream>
#include <utility>
class abc
{
public:
// general function for any variadic templated argument
template<template<typename ...> class T, typename ...TTs>
void
foo(T<TTs...>& arg)
{
std::cout << "T<TTs...>" << std::endl;
}
};
template<typename ...Ts>
struct xxx
{
// not important
};
// specialization for only variadic templated xxx
template<typename ...TTs> void
abc::foo(xxx<TTs...>& arg)
{
std::cout << "xxx<TTs...>" << std::endl;
}
// specialization for non-variadic templated xxx
template<typename TT> void
abc::foo(xxx<TT>& arg)
{
std::cout << "xxx<TT>" << std::endl;
}
// specialization for xxx<uint8_t>
template<> void
abc::foo(xxx<uint8_t>& arg)
{
std::cout << "xxx<uint8_t>" << std::endl;
}
int
main(int argc, char** argv)
{
abc p;
xxx<uint8_t> x1;
std::cout << "xxx<uint8_t> => ";
p.foo(x1);
xxx<uint16_t> x2;
std::cout << "xxx<uint16_t> => ";
p.foo(x2);
xxx<uint8_t,uint16_t> x3;
std::cout << "xxx<uint8_t,uint16_t> => ";
p.foo(x3);
std::pair<uint8_t,uint16_t> x4;
std::cout << "std::pair<uint8_t,uint16_t> => ";
p.foo(x4);
return 0;
}
,这会产生编译错误:
test_ko.cc:24:1: error: prototype for ‘void abc::foo(xxx<TTs ...>&)’ does not match any in class ‘abc’
abc::foo(xxx<TTs...>& arg)
^
test_ko.cc:10:5: error: candidate is: template<template<class ...> class T, class ... TTs> void abc::foo(T<TTs ...>&)
foo(T<TTs...>& arg)
^
test_ko.cc:31:1: error: prototype for ‘void abc::foo(xxx<TT>&)’ does not match any in class ‘abc’
abc::foo(xxx<TT>& arg)
^
test_ko.cc:10:5: error: candidate is: template<template<class ...> class T, class ... TTs> void abc::foo(T<TTs ...>&)
foo(T<TTs...>& arg)
我想要一个foo方法的特化,而不是在abc类中声明一个新的签名(因为有一个类包含模板,一个库的一部分,以及单独的特化,对于后来声明的xxx类)。
我认为使用方法的代码与具有函数的代码类似,但我在这里得到错误。我做错了什么?
答案 0 :(得分:1)
// general function for any variadic templated argument
template<template<typename ...> class T, typename ...TTs>
void
foo(T<TTs...>& arg)
{
std::cout << "T<TTs...>" << std::endl;
}
这是一个模板功能。
template<typename ...Ts>
struct xxx
{
// not important
};
// specialization for only variadic templated xxx
template<typename ...TTs> void
foo(xxx<TTs...>& arg)
{
std::cout << "xxx<TTs...>" << std::endl;
}
这不专业化。这是一个不同的模板函数,其名称foo
与上述模板函数重载。
// specialization for non-variadic templated xxx
template<typename TT> void
foo(xxx<TT>& arg)
{
std::cout << "xxx<TT>" << std::endl;
}
这不专业化。这是一个不同的模板函数,其名称foo
与上述模板函数重载。
// specialization for xxx<uint8_t>
template<> void
foo(xxx<uint8_t>& arg)
{
std::cout << "xxx<uint8_t>" << std::endl;
}
这是上述模板函数之一的完全特化。我认为第三个,但我不会赌钱。 (我相信如果您调用xxx<uint8_t>&
),它会专门用于调度foo
模板。
而不是完全专业化,我会写:
inline foo(xxx<uint8_t>& arg)
{
std::cout << "xxx<uint8_t>" << std::endl;
}
这又是foo
的全新重载。重载远不如完整功能专业化那么古怪。
没有部分模板功能专业化。
这解释了为什么尝试使用相同语法专门化方法不起作用。 也没有部分模板成员功能专业化这样的东西。
您必须在类本身中编写重载,或者调度到不同的上下文。
出错的原因是错误的直接原因是您的初始代码引入了新的重载。不允许在类定义之外引入方法的新重载,因此编译器指出了您的错误。
这是一种有用的技术。我们在abc
:
// general function for any variadic templated argument
template<template<typename ...> class T, typename ...TTs>
void foo(T<TTs...>& arg)
{
return foo(*this, arg);
}
private:
template<template<typename ...> class T, typename ...TTs>
friend void foo(abc& self, T<TTs...>& arg)
{
std::cout << "T<TTs...>" << std::endl;
}
我们的foo
方法扩展为foo
朋友。
然后我们在与abc
相同的命名空间中添加代码:
template<typename ...TTs> void
foo(abc& self, xxx<TTs...>& arg)
{
std::cout << "xxx<TTs...>" << std::endl;
}
template<typename TT> void
foo(abc& self, xxx<TT>& arg)
{
std::cout << "xxx<TT>" << std::endl;
}
inline void foo(abc& self, xxx<uint8_t>& arg)
{
std::cout << "xxx<uint8_t>" << std::endl;
}
并且在调用abc::foo
时通过ADL找到它们。