如何在非可变模板 class 中形成可变模板函数?
How to form a variadic template function within a non-variadic template class?
因此,由于我一直在学习 C++ 中的模板,所以我决定想出一些不寻常的情况,看看是否能让它们发挥作用。 (不,这不实用 - 只是为了玩弄语言!)我制作了一个模板 class,它包含一个 T
类型的值,带有一个 return 是 [= T
的 15=] 和参数包中一个值的最大值。但是,我无法编译它。这是我写的...
在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
的类型(初始化失败)。但为什么?它知道 MyClass
中 T
的类型和 pairingFunc()
中 T2
的类型。明确说明 std::pair<int, float>
修复了此错误,但保留了其他错误(潜在问题的症状)。
- "Failed to specialize function template"...我猜这意味着它不能 return 基于给定类型的类型?如果是,为什么不呢?
- "parameter pack must be expanded in this context" - 我不确定这个。将包放入数组中不会发生这种情况吗?
此外,我想通过 (T2&& head, T2&&... tail)
之类的方式强制提供至少一个参数,但我认为将这两个参数都放入数组或向量中可能很麻烦,我不确定如何按原样处理单个可变参数。所以我猜这只是 'bonus'。
根本问题是一个参数包
<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()) );
}
};
问题出在这里:
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");
它不会编译。不带参数调用它也不再可能(尽管如此,这没有任何意义)。
更好的解决方案(感谢) might be to use 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()));
}
因此,由于我一直在学习 C++ 中的模板,所以我决定想出一些不寻常的情况,看看是否能让它们发挥作用。 (不,这不实用 - 只是为了玩弄语言!)我制作了一个模板 class,它包含一个 T
类型的值,带有一个 return 是 [= T
的 15=] 和参数包中一个值的最大值。但是,我无法编译它。这是我写的...
在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
的类型(初始化失败)。但为什么?它知道MyClass
中T
的类型和pairingFunc()
中T2
的类型。明确说明std::pair<int, float>
修复了此错误,但保留了其他错误(潜在问题的症状)。 - "Failed to specialize function template"...我猜这意味着它不能 return 基于给定类型的类型?如果是,为什么不呢?
- "parameter pack must be expanded in this context" - 我不确定这个。将包放入数组中不会发生这种情况吗?
此外,我想通过 (T2&& head, T2&&... tail)
之类的方式强制提供至少一个参数,但我认为将这两个参数都放入数组或向量中可能很麻烦,我不确定如何按原样处理单个可变参数。所以我猜这只是 'bonus'。
根本问题是一个参数包
<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()) );
}
};
问题出在这里:
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");
它不会编译。不带参数调用它也不再可能(尽管如此,这没有任何意义)。
更好的解决方案(感谢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()));
}