重载C ++模板函数 [英] Overloading of C++ templated functions

查看:132
本文介绍了重载C ++模板函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为以下代码应该工作,但是g ++和clang ++都返回完全相同的错误(虽然Visual C ++ 2012没有)。

I would think that the following code should be working, but both g++ and clang++ return the exact same error (although Visual C++ 2012 doesn't).

#include <iostream>
#include <tuple>

template <int N, typename T>
struct A { };

template <typename Tuple>
double result(const Tuple& t, const A<0, typename std::tuple_element<0, Tuple>::type>& a)
{
  return 0;
}

template <typename Tuple>
double result(const Tuple& t, const A<std::tuple_size<Tuple>::value-1,
                                      typename std::tuple_element<std::tuple_size<Tuple>::value-1,Tuple>::type>& a)
{
  return 1;
}

template <typename Tuple, int N>
double result(const Tuple& t, const A<N, typename std::tuple_element<N, Tuple>::type>& a)
{
  return 0.5;
}

int main()
{
  auto a = std::make_tuple(0, 1, 2., 3., 4);
  std::cout << result(a, A<0,int>()) << std::endl;
  std::cout << result(a, A<2,double>()) << std::endl;
  std::cout << result(a, A<4,int>()) << std::endl; // Fails if uncommented
  return 0;
}

错误是由于最后一行和第二和第三 result 函数被视为等效。虽然我认为第二个比第三个更好(比如第一个)。

The error is due to the last line and the fact that the second and third result functions are considered equivalent. Although I would think the second one is a better fit than the third one (like the first one is).

我不知道。

推荐答案

TLDR; 原因是什么?你的程序无法编译是第二和第三个过载是同样好的匹配过载分辨率。特别是,两者都不比另一个更专业。因为重载分辨率不能选择最佳匹配,所以程序是不成形的。

TLDR; The reason that your program fails to compile is that the second and third overload are equally good matches during overload resolution. In particular, neither is more specialized than the other. Because overload resolution cannot select a best match, the program is ill-formed. The cure is to SFINAE your way out of it.

14.5.6.2部分函数模板的排序[temp.func.order]


2部分排序选择两个函数模板中的哪一个更多
通过依次转换每个模板(参见
下一段)并使用
函数类型执行模板参数扣除来实现。扣除过程确定
模板中的一个是否比另一个更专门化。如果是这样,更多的
专用模板是由部分排序
过程选择的模板。

2 Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process.

3要生成转换的模板,请为每个类型生成
非类型或模板模板参数(包括模板参数
pack(14.5。 3))分别合成唯一的类型,值或类别
模板,并且在模板的函数类型中的
参数的每次出现时替换它。

3 To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs (14.5.3) thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template.

对于所有三个重载,第一个合成参数是相等的,因为所有的参数都是一个接一个,所以我们可以专注于第二个。

For all three overloads, the first synthesized argument is equal, and since all arguments are considered one by one, we can focus on the second one.

您的第一个超载转换为以下合成的第二个参数

Your first overload is transformed to the following synthesized 2nd argument

const A<0, typename std::tuple_element<0, Arg1>::type>&

您的第二个重载转换为以下合成的第二个参数

Your second overload is transformed to the following synthesized 2nd argument

const A<
        std::tuple_size<Arg1>::value-1, typename        
        std::tuple_element<std::tuple_size<Arg1>::value-1, Arg1>::type
>&

您的第三个重载转换为以下合成的第二个参数

Your third overload is transformed to the following synthesized 2nd argument

const A<Arg2, typename std::tuple_element<Arg2, Arg1>::type>&    

14.8.2.4在部分排序期间扣除模板参数[temp.deduct.partial] strong>

14.8.2.4 Deducing template arguments during partial ordering [temp.deduct.partial]


2两组类型用于确定部分排序。对于
,每个涉及的模板是原始函数类型,
是转换的函数类型。 [注:转换的
类型的创建在14.5.6.2中描述。 - end note]扣除过程使用转换类型
作为参数模板,原始类型
将另一个模板用作参数模板。对于部分排序比较中涉及的每个类型,这个过程是
两次:使用转换的模板-1作为参数模板的
和作为参数模板的
template-2,并再次使用转换
模板-2作为参数模板,并将模板-1作为参数
模板。

2 Two sets of types are used to determine the partial ordering. For each of the templates involved there is the original function type and the transformed function type. [ Note: The creation of the transformed type is described in 14.5.6.2. — end note ] The deduction process uses the transformed type as the argument template and the original type of the other template as the parameter template. This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template.

清除第一和第二过载没有第二模板参数来推断,因此它们至少与第三过载一样专门。问题是第三个是否可以有从第一个和第二个重载的合成第二个参数推导的 N 参数。

It is clear that the first and second overload have no 2nd template parameter to deduce and so they are at least as specialized as the third overload. The question is whether the third can have it's N parameter deduced from the first and second overloads' synthesized 2nd argument.

对于第一个重载,这对于 N = 0 是正确的,因此第一个重载比第三。这是为什么你的第一个函数调用选择第一个重载。

For the first overload, this is true for N=0, and so the first overload is more specialized than the third. This is why your first function call selects the first overload.

对于第三个重载,参数deduction不会发生,它是一个非推导的上下文:

For the third overload, argument deduction does not take place it is a non-deduced context:

14.8.2.5从类型[temp.deduct.type]中导入模板参数


5非推导的上下文是:

5 The non-deduced contexts are:

- ...

strong>非类型模板参数或数组绑定,其中子表达式引用模板参数。

A non-type template argument or an array bound in which a subexpression references a template parameter.

- ...

这意味着第三次重载也至少与第二次重载相同。因此,重载解决不能选择一个,程序是不成形的。

This means that the third overload is also at least as specialized as the second one. Hence, overload resolution is not able to select one, and the program is ill-formed.

只需在 enable_if (使用SFINAE)中使用非重叠条件进行两个重载。在这种情况下,这绕过了重载解析。

Simply make two overloads with a non-overlapping condition inside an enable_if (using SFINAE). This bypasses overload resolution in this case.

template <typename Tuple, int N>
typename std::enable_if<N == std::tuple_size<Tuple>::value-1, double>::type
result(const Tuple& t, const A<N, typename std::tuple_element<N, Tuple>::type>& a)
{
  return 1;
}

template <typename Tuple, int N>
typename std::enable_if<N != std::tuple_size<Tuple>::value-1, double>::type
result(const Tuple& t, const A<N, typename std::tuple_element<N, Tuple>::type>& a)
{
  return 0.5;
}

活动示例

这篇关于重载C ++模板函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆