【问题标题】:Unexpected overload called when function is called from variadic template instantiation从可变参数模板实例化调用函数时调用了意外的重载
【发布时间】:2012-10-28 13:23:10
【问题描述】:

假设以下代码:

#include <iostream>

template<typename... T>
void foo(const T &...);

template<unsigned N>
void foo(const char (&)[N])
{
   std::cout << "char(&)[N]" << std::endl;
}

void foo(const char *)
{
   std::cout << "const char *" << std::endl;
}

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

template<typename First, typename... T>
void foo(const First & first, const T &... rest)
{
   std::cout << "Generic + " << sizeof...(T) << std::endl;
   foo(first);
   foo(rest...);
}

int main()
{
    const char * c = "asdf";
    char a[] = {'a', 'b', 'c', 'd'};
    foo('f', c, a, 1);
    foo(a);
}

The output is:

Generic + 3
Single              // fine; 'f' is `char` -> generic
Generic + 2
const char *        // fine; c is `const char *`
Generic + 1
const char *        // (!) not fine
Single
char(&)[N]          // fine; a is char[4]

最后一次调用 - foo(a),其中 achar[4] - 调用我期待的版本 - template&lt;unsigned N&gt; void foo(const char (&amp;)[N])。但是为什么foo的可变参数模板的实例化不调用foo(const char (&amp;)[N],而是调用foo(const char *)呢?如果没有 char 数组重载,那应该是可以预料的——但为什么会发生在这里? const First &amp; 不应该正确捕获数组类型吗?

另外,使泛型可变参数版本与传递给它的数组一起正常工作的最简单方法是什么?


Matthieu M. 在 cmets 中注意到,问题可能不是由可变参数模板引起的,而是由 indirection 引起的:

#include <iostream>

template <unsigned N>
void foo(const char (&)[N])
{
   std::cout << "char(&)[N]" << std::endl;
}

void foo(const char *)
{
   std::cout << "const char *" << std::endl;
}

template <typename T>
void goo(T const& t) {
    foo(t);
}

int main()
{
    char a[] = {'a', 'b', 'c', 'd'};
    foo(a);
    goo(a);
}
字符(&)[N] 常量字符 *

他还说这可能是编译器错误 - 尽管代码在 Clang 3.2 dev、G++ 4.6 和 4.7 中产生完全相同的结果。

R. Martinho Fernandes 指出,将最后一个 sn-p 中的 a 的类型更改为 const char a[] 会使代码产生两次 const char *

【问题讨论】:

  • 为什么是// fine; "afas" is const char *?它不是! ideone.com/4KewDe
  • 我设法进一步减少了问题here。显然,间接导致了这个问题,而可变参数与此无关。不过仍然没有找到可能的解释……在我看来,这肯定是一个编译器错误。
  • @MatthieuM。 Mind the const.
  • 见这里:stackoverflow.com/questions/5173494/… 很好解释这是因为非模板函数的精确匹配......
  • @PiotrNycz:该死的!那时是黑魔法(我多么希望“数组”类型更强大......)

标签: c++ templates forwarding variadic-templates


【解决方案1】:

我想我可以回答第二部分:如何解决?我不确定我是否得到了正确的答案,因为在我看来,传递字符串文字的情况仍然会产生错误的结果。修复的基本思想是使用完美转发,而不是希望为T const&amp; 推断出正确的类型。为什么将T const&amp; 与数组一起使用会导致数组衰减,不过我还不太明白。

当然,使用完美前向意味着执行它的函数是完美匹配的,并且某些专业化实际上会进行一些转换,至少添加const。因此,有必要使用不同的名称。总的来说,这看起来像这样:

#include <iostream>
#include <utility>

void foo()
{
}

template<unsigned N>
void special(const char (&)[N])
{
    std::cout << "char(&)[" << N << "]" << '\n';
}

void special(const char *)
{
   std::cout << "const char *" << '\n';
}

template<typename T>
void special(const T &)
{
   std::cout << "Single" << '\n';
}

template<typename First, typename... T>
void foo(First&& first, T&&... rest)
{
   std::cout << "Generic + " << sizeof...(T) << '\n';
   special(std::forward<First>(first));
   foo(std::forward<T>(rest)...);
}

int main()
{
    char const* c("foo");
    char a[] = {'a', 'b', 'c', 'd'};
    foo('f', "afas", a, c, 1);
    foo(a);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多