为派生的可变参数类模板调用函数模板重载

时间:2013-02-03 22:54:03

标签: c++ templates c++11

我有一个可变参数类模板deriv,它派生出可变参数类模板base

我有一个函数模板,它接受任何类型T,以及base<Ts...>类型的重载;

如何在传递base<Ts...>时使用const deriv<Ts...>&重载?

以下工作示例:

#include <iostream>
#include <tuple>

template<typename... Ts>
struct base
{
    std::tuple<Ts...> tuple;
};

template<typename... Ts>
struct deriv : base<Ts...>
{
};

//--------------------------------

template<typename T>
void func(const T&)
{
    std::cout << "T" << std::endl;
}

template<typename... Ts>
void func(const base<Ts...>&)
{
    std::cout << "base<Ts...>" << std::endl;
}

//----------------------------------------

int main()
{
    int a;
    base <int, double> b;
    deriv<int, double> c;

    func(a);
    func(b);
    func(c); // <--- I want func<base<Ts...>> not func<T> to be called here

    exit(0);
}

来自示例的输出:

T
base<Ts...>
T

我想要的输出是什么:

T
base<Ts...>
base<Ts...>

2 个答案:

答案 0 :(得分:6)

除非您已准备好重新设计代码,您不能,并且有充分的理由。

func()的非变量重载是更好的匹配而不是可变参数版本:实际上,在尝试解析函数调用时,类型参数T为非可变重载将推导为derived<int, double>

另一方面,可变参数重载中的参数包Ts将推导为int, double。在类型推断之后,这实际上会让编译器有两个选择来解析你的调用:

void func(const deriv<int, double>&); // Non-variadic after type deduction
void func(const base<int, double>&);    // Variadic after type deduction

在尝试匹配参数类型为derived<int, double>的调用时,应该选择哪一个?

deriv<int, double> c;
func(c);

显然,第一个非可变超载是更好的匹配

那你如何得到第二个重载而不是第一个呢?你有几个选择。首先,您可以通过显式指定模板参数来限定您的调用:

func<int, double>(c);

如果您不喜欢这样,也许您可​​以重新考虑func()的非变量重载的定义:您是否真的希望它接受任何可能的类型{{ 1}?或者是否有一些类型您知道不会调用此重载?如果是这样,您可以使用SFINAE技术和T来排除不受欢迎的匹配。

作为另一种可能性,您可以放松一下模板函数的签名,并允许将其参数推断为某个模板类的实例化:

std::enable_if

仅此更改应以您希望的方式修复程序的行为。

<强>更新

如果您希望为从template<template<typename...> class T, typename... Ts> void func(const T<Ts...>&) { std::cout << "base<Ts...>" << std::endl; } 类模板的任何实例派生的类调用专用函数模板 ,则可以使用base<>类型特征和{ {1}}通过以下方式:

std::is_base_of<>

<强>附录:

在模板函数重载对您的设计没有帮助的情况下,请注意您始终可以使用部分模板专业化。遗憾的是,函数模板不能专门化,但您仍然可以利用模板部分特化并添加辅助函数来隐藏该模板的实例化。这就是你重写代码的方式:

std::enable_if

答案 1 :(得分:0)

泛型模板重载是一个更好的匹配,因为它不需要转换(除了添加const,两个重载都有)。

您可以通过添加显式广播(example)来获取base - 模板重载:

func(static_cast<base<int, double> &>(c));

(或者,您可以放弃多次重载,而是将一些is_base_of辅助逻辑粘贴到主函数模板的主体中。)