模板模板函数的重载 - 显式调用

时间:2017-03-30 17:20:30

标签: c++ templates template-templates

因此,首先考虑下面的函数参数隐式知道模板参数:

#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>

但是,如果我没有类CD的实例,那么我需要明确调用正确的重载怎么办?怎么做?即,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>形式?或者我遇到了障碍,需要重新修改现有的一些框架吗?

3 个答案:

答案 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>());