因此,首先考虑下面的函数参数隐式知道模板参数:
#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>
但是,如果我没有类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:
我想要做什么甚至是允许的?如果是这样,我在哪里弄乱?
----编辑----
正如苹果苹果指出我的main()
如下:
int main() {
foo<C, A, B>();
foo<D, A>();
}
我按预期得到了输出。
然而,我的现实案例变得更加复杂。我会在这里扩展一下。遗留代码在其他地方的标题中定义了(数百个)typedef:
typedef C<A, B> type_117;
typedef D<A> type_252;
我正在处理的类是模板化的,并使用其中一个typedef作为模板参数进行实例化。所以有些东西:
template <class Type>
class Test
{
public:
Test();
SomeClass mSC;
}
Test::Test()
: mSC(foo<Type>())
{
};
将Test实例化为
Test<type_117> aTest;
所以我一直试图弄清楚如何为这个背景写foo()
。在我foo()
的初始化程序中调用Test
之后,我能够&#34;分解&#34;它产生<C,A,B>
形式?或者我遇到了障碍,需要重新修改现有的一些框架吗?
答案 0 :(得分:2)
考虑到禁止部分专业化的功能;所以很难做到你究竟问的是什么。
来自apple apple的建议(将调用称为foo<C, A, B>()
是一个很好的建议但是,如果你想保持原始调用(foo<C<A, B>>()
),你可以使用允许部分特化的事实对于结构/类,并为仿函数创建部分特化;类似
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; }
};
问题(?)是,调用它,你不能称为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问
我对部分专业化并不熟悉;你能扩展一下我的尝试方式吗?
专业化(部分和全部)是一个重大的主题。
只是一些例子,给出一个想法。
给定模板类/ 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> ()
{ }
答案 1 :(得分:2)
您可以使用部分特化(和可变参数模板):
a = b = 1
c = -7
puts "%0.1fX + %0.1fY %s %0.1f = %d"%[ a, b, c < 0 ? '-' : '+', c.abs, 0 ]
答案 2 :(得分:2)
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>)
和bob,正如他们所说,是你的叔叔。
在C ++ 98(ick)中:
template<class T>struct tag_t{};
foo(tag_t<type_117>());