模板模板函数的重载 - 显式调用
overload of template template function - explicit call
因此,首先考虑以下从函数参数中隐式知道模板参数的情况:
#include <iostream>
using namespace std;
class A {};
class B {};
template <class T1, class T2>
class C {
T1 a;
T2 b;
};
template <class T1>
class D {
T1 a;
};
template <template<class, class> class TC, class TA, class TB>
void foo(TC<TA, TB> c) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(TD<TA> d){
std::cout << "T<T>" << std::endl;
};
int main() {
C<A,B> c;
D<A> d;
foo(c);
foo(d);
}
输出如您所料:
T<T,T>
T<T>
但是,如果我没有 class C
和 D
的实例,那么我需要显式调用正确的重载怎么办?这将如何完成?即,main()
包含:
int main() {
foo<C<A,B> >();
foo<D<A> >();
}
我尝试了一些 foo()
的重载,如下所示:
template <template<class, class> class TC>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD>
void foo(){
std::cout << "T<T>" << std::endl;
};
template <template<class, class> class TC, class TA, class TB>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(){
std::cout << "T<T>" << std::endl;
};
然而,这(以及我能想到的所有排列)只会导致如下所示(缩写)输出的一系列错误
prog.cpp: In function 'int main()':
prog.cpp:44:18: error: no matching function for call to 'foo()'
foo<C<A,B> >();
^
prog.cpp:44:18: note: candidates are:
prog.cpp:19:6: note: template<template<class, class> class TC> void foo()
void foo() {
^
prog.cpp:19:6: note: template argument deduction/substitution failed:
prog.cpp:24:6: note: template<template<class> class TD> void foo()
void foo(){
^
prog.cpp:24:6: note: template argument deduction/substitution failed:
我想做的事情是否允许?如果是这样,我哪里搞砸了?
---- 编辑 ----
正如 apple apple 指出的那样,如果我的 main()
如下:
int main() {
foo<C, A, B>();
foo<D, A>();
}
我得到了预期的输出。
然而,我的 real-world 案例最终变得更加复杂。我会在这里展开一点。遗留代码在 headers 其他地方定义了(数百个)typedefs:
typedef C<A, B> type_117;
typedef D<A> type_252;
我正在处理的 class 是模板化的,并使用其中一个 typedef 作为模板参数进行了实例化。所以类似的东西:
template <class Type>
class Test
{
public:
Test();
SomeClass mSC;
}
Test::Test()
: mSC(foo<Type>())
{
};
其中 Test 被实例化为
Test<type_117> aTest;
所以我一直在努力弄清楚如何为这种情况编写 foo()
。在我 Test
的初始值设定项中调用 foo()
时,我是否能够 "decompose" 它生成 <C,A,B>
形式?还是我遇到了障碍,需要重新设计一些现有的框架?
考虑到函数禁止偏特化;所以很难按照你的要求去做。
apple apple (chenge the calling as foo<C, A, B>()
的建议很好,但是,如果你想保持原来的调用 (foo<C<A, B>>()
),你可以使用偏特化的事实允许 structs/classes 并为仿函数创建部分特化;类似于
template <typename>
struct bar;
template <template<typename, typename> class Tc, typename Ta, typename Tb>
struct bar<Tc<Ta,Tb>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta, Tb>>()" << std::endl; }
};
template <template<typename> class Tc, typename Ta>
struct bar<Tc<Ta>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta>>()" << std::endl; }
};
问题(?)是,调用它,你不能调用 as bar<C<A,B>>()
od bar<D<A>>()
但你必须添加几个括号:
bar<C<A,B>>()();
bar<D<A>>()();
或
bar<C<A,B>>{}();
bar<D<A>>{}();
我想仿函数解决方案也可以解决您问题的编辑部分的问题。
如果添加的一对括号有问题,您可以(按照 Jarod42 的建议(谢谢!))将调用包装在模板函数中,如下所示
template <typename T>
void bar ()
{ bar<T>{}(); }
因此您可以调用 bar<C<A, B>>()
函数并在专门的 bar<C<A, B>>
结构中管理调用。
另请注意 Jarod42 的解决方案:根据您的要求,您可以只开发 bar
.
的部分专业化版本
-- 编辑 --
OP 问
I'm not that familiar with partial specialization; could you expand a bit on how what I was trying was?
专业化(部分和完全)是一个很大很大的话题。
举个例子,给大家一个思路。
给定一个模板class/struct
template <typename X, typename Y>
struct foo
{ };
您可以 部分 将其特化如下(通过示例)
template <typename X>
struct foo<X, X>
{ };
当特化维护模板变量时,或者您可以完全特化如下(通过示例)
template <>
struct foo<int, long>
{ };
其中所有模板参数都是固定的。
好吧:使用函数你可以完全专业化但不能部分专业化。
所以你可以写一个模板函数
template <typename X, template Y>
void foo ()
{ }
并完全专业化它
template <>
void foo<int, long> ()
{ }
但是你不能部分专业化它;所以你不能写(是一个错误)
template <typename X>
void foo<X, X> ()
{ }
您可以使用部分特化(和可变参数模板):
template <class Type>
class Test;
template <template <typename ...> class C, typename ... Ts>
class Test<C<Ts...>>
{
public:
Test() : mSC(foo<C, Ts...>()) {}
SomeClass mSC;
};
template<class T>struct tag_t{constexpr tag_t(){}};
template<class T>constexpr tag_t<T> tag{};
这些是类型标签。它们可以传递给没有类型实例的函数。
模板函数将推导它们。
template <template<class, class> class TC, class TA, class TB>
void foo(tag_t<TC<TA, TB>>) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(tag_t<TD<TA>>){
std::cout << "T<T>" << std::endl;
};
在呼叫站点做 foo(tag<type_117>)
和鲍勃,正如他们所说,是你的叔叔。
在 C++98 中(恶心):
template<class T>struct tag_t{};
foo(tag_t<type_117>());
因此,首先考虑以下从函数参数中隐式知道模板参数的情况:
#include <iostream>
using namespace std;
class A {};
class B {};
template <class T1, class T2>
class C {
T1 a;
T2 b;
};
template <class T1>
class D {
T1 a;
};
template <template<class, class> class TC, class TA, class TB>
void foo(TC<TA, TB> c) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(TD<TA> d){
std::cout << "T<T>" << std::endl;
};
int main() {
C<A,B> c;
D<A> d;
foo(c);
foo(d);
}
输出如您所料:
T<T,T>
T<T>
但是,如果我没有 class C
和 D
的实例,那么我需要显式调用正确的重载怎么办?这将如何完成?即,main()
包含:
int main() {
foo<C<A,B> >();
foo<D<A> >();
}
我尝试了一些 foo()
的重载,如下所示:
template <template<class, class> class TC>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD>
void foo(){
std::cout << "T<T>" << std::endl;
};
template <template<class, class> class TC, class TA, class TB>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(){
std::cout << "T<T>" << std::endl;
};
然而,这(以及我能想到的所有排列)只会导致如下所示(缩写)输出的一系列错误
prog.cpp: In function 'int main()':
prog.cpp:44:18: error: no matching function for call to 'foo()'
foo<C<A,B> >();
^
prog.cpp:44:18: note: candidates are:
prog.cpp:19:6: note: template<template<class, class> class TC> void foo()
void foo() {
^
prog.cpp:19:6: note: template argument deduction/substitution failed:
prog.cpp:24:6: note: template<template<class> class TD> void foo()
void foo(){
^
prog.cpp:24:6: note: template argument deduction/substitution failed:
我想做的事情是否允许?如果是这样,我哪里搞砸了?
---- 编辑 ----
正如 apple apple 指出的那样,如果我的 main()
如下:
int main() {
foo<C, A, B>();
foo<D, A>();
}
我得到了预期的输出。
然而,我的 real-world 案例最终变得更加复杂。我会在这里展开一点。遗留代码在 headers 其他地方定义了(数百个)typedefs:
typedef C<A, B> type_117;
typedef D<A> type_252;
我正在处理的 class 是模板化的,并使用其中一个 typedef 作为模板参数进行了实例化。所以类似的东西:
template <class Type>
class Test
{
public:
Test();
SomeClass mSC;
}
Test::Test()
: mSC(foo<Type>())
{
};
其中 Test 被实例化为
Test<type_117> aTest;
所以我一直在努力弄清楚如何为这种情况编写 foo()
。在我 Test
的初始值设定项中调用 foo()
时,我是否能够 "decompose" 它生成 <C,A,B>
形式?还是我遇到了障碍,需要重新设计一些现有的框架?
考虑到函数禁止偏特化;所以很难按照你的要求去做。
apple apple (chenge the calling as foo<C, A, B>()
的建议很好,但是,如果你想保持原来的调用 (foo<C<A, B>>()
),你可以使用偏特化的事实允许 structs/classes 并为仿函数创建部分特化;类似于
template <typename>
struct bar;
template <template<typename, typename> class Tc, typename Ta, typename Tb>
struct bar<Tc<Ta,Tb>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta, Tb>>()" << std::endl; }
};
template <template<typename> class Tc, typename Ta>
struct bar<Tc<Ta>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta>>()" << std::endl; }
};
问题(?)是,调用它,你不能调用 as bar<C<A,B>>()
od bar<D<A>>()
但你必须添加几个括号:
bar<C<A,B>>()();
bar<D<A>>()();
或
bar<C<A,B>>{}();
bar<D<A>>{}();
我想仿函数解决方案也可以解决您问题的编辑部分的问题。
如果添加的一对括号有问题,您可以(按照 Jarod42 的建议(谢谢!))将调用包装在模板函数中,如下所示
template <typename T>
void bar ()
{ bar<T>{}(); }
因此您可以调用 bar<C<A, B>>()
函数并在专门的 bar<C<A, B>>
结构中管理调用。
另请注意 Jarod42 的解决方案:根据您的要求,您可以只开发 bar
.
-- 编辑 --
OP 问
I'm not that familiar with partial specialization; could you expand a bit on how what I was trying was?
专业化(部分和完全)是一个很大很大的话题。
举个例子,给大家一个思路。
给定一个模板class/struct
template <typename X, typename Y>
struct foo
{ };
您可以 部分 将其特化如下(通过示例)
template <typename X>
struct foo<X, X>
{ };
当特化维护模板变量时,或者您可以完全特化如下(通过示例)
template <>
struct foo<int, long>
{ };
其中所有模板参数都是固定的。
好吧:使用函数你可以完全专业化但不能部分专业化。
所以你可以写一个模板函数
template <typename X, template Y>
void foo ()
{ }
并完全专业化它
template <>
void foo<int, long> ()
{ }
但是你不能部分专业化它;所以你不能写(是一个错误)
template <typename X>
void foo<X, X> ()
{ }
您可以使用部分特化(和可变参数模板):
template <class Type>
class Test;
template <template <typename ...> class C, typename ... Ts>
class Test<C<Ts...>>
{
public:
Test() : mSC(foo<C, Ts...>()) {}
SomeClass mSC;
};
template<class T>struct tag_t{constexpr tag_t(){}};
template<class T>constexpr tag_t<T> tag{};
这些是类型标签。它们可以传递给没有类型实例的函数。
模板函数将推导它们。
template <template<class, class> class TC, class TA, class TB>
void foo(tag_t<TC<TA, TB>>) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(tag_t<TD<TA>>){
std::cout << "T<T>" << std::endl;
};
在呼叫站点做 foo(tag<type_117>)
和鲍勃,正如他们所说,是你的叔叔。
在 C++98 中(恶心):
template<class T>struct tag_t{};
foo(tag_t<type_117>());