2

所以,当我一直在学习 C++ 中的模板时,我决定想出一些不寻常的情况,看看我是否能让它们工作。(不,这不切实际 - 只是为了玩语言!)我创建了一个模板类,它包含一个 type 的值T,带有一个可变参数函数模板,它返回参数包中的一个std::pairT和最大值。但是,我无法编译它。这是我写的...

header.h中:

#ifndef HEADER_H
#define HEADER_H

#include <utility>
#include <algorithm>
#include <array>

template <typename  T>
class MyClass
{

  T m_heldType;

public:

  MyClass(T t) : m_heldType(t) {}

  template <typename... T2>
  std::pair<T, T2> pairingFunc(T2&&... types)
  {
    std::array<T2, sizeof...(types)> types_arr = { types... };

    return std::make_pair( m_heldType, *std::max_element(types_arr.begin(), types_arr.end()) );
  }

};

#endif

source.cpp中:

#include <iostream>
#include "Header.h"

int main()
{
  MyClass<int> mc(512);

  auto mypair = mc.pairingFunc(1.61f, 3.14f, 6.66f);

  std::cout << mypair.first << ' ' << mypair.second;
  std::cin.ignore();
}

这些是我产生的错误:

Error   C3520   'T2': parameter pack must be expanded in this context   ...\header.h    24
Error   C2672   'MyClass<int>::pairingFunc': no matching overloaded function found  ...\source.cpp  8
Error   C2893   Failed to specialize function template 'std::pair<T,T2> MyClass<T>::pairingFunc(T2 &&...)'  ...\source.cpp  8
Error   C3536   'mypair': cannot be used before it is initialized   ...\source.cpp  10
Error   C2228   left of '.first' must have class/struct/union   ...\source.cpp  10
Error   C2228   left of '.second' must have class/struct/union  ...\source.cpp  10

所以这就是我的想法:

  • 显然,编译器无法确定mypair(初始化失败)的类型。但为什么?它知道in的类型和TinMyClass的类型。明确说明修复了这个错误,但留下了其他错误(潜在问题的症状)。T2pairingFunc()std::pair<int, float>
  • “无法专门化函数模板”......我猜这意味着它无法根据给定的类型返回类型?如果是这样,为什么不呢?
  • “必须在这种情况下扩展参数包” - 我不确定这个。通过将包放入数组中不会发生这种情况吗?

此外,我想通过类似的方式强制提供至少一个参数(T2&& head, T2&&... tail),但我认为将这两个参数都放入数组或向量中可能会很讨厌,而且我不确定如何只处理单个可变参数是。所以我猜这只是一个“奖金”。

4

2 回答 2

2

根本问题是参数包

<typename ...T2>

不代表单一类型。

 template <typename... T2>
 void foo(T2 && ...args)

这个参数包可以接受类型的组合,即

 foo(4, "bar", Baz());

您需要弄清楚pairingFunc()接收的参数的类型。建议std::common_type_t是一个不错的选择:

template <typename  T>
class MyClass
{

    T m_heldType;

public:

    MyClass(T t) : m_heldType(t) {}

    template <typename ...T2>
    auto pairingFunc(T2 &&...values)
    {
        std::array<std::common_type_t<T2...>, sizeof...(T2)> types_arr = { values... };

        return std::make_pair( m_heldType, *std::max_element(types_arr.begin(), types_arr.end()) );
    }

};
于 2016-08-27T15:28:15.873 回答
2

问题在这里:

std::pair<T, T2> pairingFunc(T2&&... types)
             ^^

和这里

std::array<T2, sizeof...(types)> types_arr = { types... };
           ^^

T2是一个参数包,而不是一个类型。它可以存储多种类型,即1.4f, "hi", 1, 0.5. 因此,您不能将其用作单一类型,这是不可能的。您需要引入另一个参数并将其用作类型:

template <typename T1, typename... T2>
std::pair<T, T1> pairingFunc(T1&& arg, T2&&... types)
{
    std::array<T1, sizeof...(types) + 1> types_arr = { arg, types... };

    return std::make_pair(m_heldType, *std::max_element(types_arr.begin(), types_arr.end()));
}

这也有一个好处,如果你打电话

mc.pairingFunc(4.5f, "hello");

它不会编译。也不再可能在没有参数的情况下调用它(尽管如此,这没有意义)。


一个更好的解决方案(感谢@DanielSchepler)可能是使用std::common_type,因为第二个参数可能不能转换为T,但T可以转换为第二个参数:

template <typename T1, typename... T2>
std::pair<T, std::common_type_t<T1, T2...>> pairingFunc(T1&& arg, T2&&... types)
{
    std::array<std::common_type_t<T1, T2...>, sizeof...(types) + 1> types_arr = { arg, types... };

    return std::make_pair(m_heldType, *std::max_element(types_arr.begin(), types_arr.end()));
}
于 2016-08-27T15:30:40.580 回答