【问题标题】:Type deduction and argument passing with variadic template templates使用可变参数模板模板进行类型推导和参数传递
【发布时间】:2012-11-24 00:56:14
【问题描述】:

由于可变参数模板,我不久前实现了 Python 的链函数的 C++ 等价物。该函数用于连续迭代多个容器。这是使用名为 ChainedObject 的生成器的函数的旧工作版本,无论它是什么:

template<typename... Iterables>
auto chain(Iterables&&... iters)
    -> ChainObject<Iterables...>
{
    return /* ... */;
}

以及对应的main:

int main()
{
    std::vector<int> vec = { 1, 2, 3, 4, 5 };
    std::list<int>   li  = { 6, 7, 8, 9, 10, 11, 12, 13 };
    for (auto& i: chain(vec, li))
    {
        // You can edit a range of iterables
        // as if there was only one of them.
        i *= 5;

        std::cout << i << std::endl;
    }
    return 0;
}

那个主要工作正常。我们不在乎 ChainObject 中有什么问题,所以让我们看看。我尝试使用模板模板来确保使用的不同集合具有相同的value_type,并通过以下方式修改了函数chain

template<typename T, template<typename...> class... Iterables>
auto chain(Iterables<T>&&... iters)
    -> ChainObject<T, Iterables...>
{
    return /* ... */;
}

我认为这样可以确保我之前的 main 中的 listvector 共享相同的类型,但相反,我从 GCC 4.7.1 收到以下错误:

在函数'int main()'中:

错误:没有匹配函数调用 'chain(std::vector&, std::list&)'

注意:候选人是:

注意:ChainObject&lt;T, Iterables ...&gt; chain(Iterables&lt;T&gt;&amp;&amp; ...) [with T = int; Iterables = {std::vector, std::list}]

注意:没有已知的参数 2 从“std::list&lt;int&gt;”到“std::list&lt;int&gt;&amp;&amp;”的转换

注:ChainObject&lt;T, Iterables ...&gt; chain(Iterables&lt;T&gt;&amp;&amp; ...) [with T = int; Iterables = {std::vector, std::list}]

注意:没有已知的参数 2 从“std::list&lt;int&gt;”到“std::list&lt;int&gt;&amp;&amp;”的转换

错误:无法从 '' 推断出 'auto&'

问题似乎来自于将参数传递给采用右值引用的函数。但是,我真的不明白为什么我的第一个版本运行良好,请注意使用模板模板的版本。

【问题讨论】:

  • 您是否尝试过传递左值引用而不是右值?
  • 不要将模板模板与容器结合使用。一旦使用分配器,它就会失败。只需检查嵌套的value_type 是否相等。

标签: c++ templates c++11 rvalue-reference template-templates


【解决方案1】:

您的问题是 T&amp;&amp; 模板魔法仅适用于类型参数(它通过推导 T 例如。int&amp; 如果需要 - 对于左值参数)。它不适用于模板模板参数,其中实际类型为X&lt;T&gt;&amp;&amp; - 在这种情况下X 必须是类模板,而不是类似“reference-to-class-template”的东西。所以最后你必须传递一个右值引用,你不能从左值(变量)中隐式获取它。

也就是说,我建议您恢复到之前的代码并检查 value_types 是否与 SFINAE 相同(或兼容等,无论您如何使用)。

粗略的代码草图(用于严格相等):

template <class ... Ts> struct all_types_equal
{
  static const bool value = false;
};

template <class T>
struct all_types_equal<T>
{
  static const bool value = true;
};
template <class T, class ... Rest>
struct all_types_equal<T, T, Rest...>
{
  static const bool value = all_types_equal<T, Rest...>::value;
};

template<typename... Iterables>
auto chain(Iterables&&... iters)
    -> typename std::enable_if<all_types_equal<Iterable::value_type...>::value, ChainObject<Iterables...> >::type

【讨论】:

  • 非常感谢。看来我还有很多东西要学 C++。然后我将恢复使用普通的旧enable_if :)
  • 我试过了,正确的返回类型是typename std::enable_if&lt;all_types_equal&lt;typename std::decay&lt;Iterables&gt;::type::value_type...&gt;::value, ChainObject&lt;Iterables...&gt;&gt;::type
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-09
  • 1970-01-01
相关资源
最近更新 更多