可以在可变参数模板中推导出容器类型吗?
Can the container type be deduced in variadic templates?
在 C++11/C++14 中,
template <
typename T ,
template <typename...> class Container_t
>
void MyFunc(Container_t<T> &data) { ... }
template <typename T>
void MyFunc2( T v ) { ... }
int main()
{
std::vector<char> v;
MyFunc<char, std::vector>(v); // OK
MyFunc(v); // error
int i;
MyFunc2<int>(i); // OK
MyFunc2(i); // OK
}
我在 MyFunc(v)
中遇到错误。
有没有办法让编译器找出传递给可变参数模板函数的容器类型?我发现找到它没有问题,就像普通模板中的普通类型一样。
如果我需要更改 v 的类型,是否必须修复对 MyFunc 的所有调用?
编译器:Microsoft Visual C++ 2015 (v140)
与其尝试推断容器类型,不如假设容器定义了它存储的类型。
template <typename Container>
void MyFunc(Container& data)
{
// all std containers defines value_type member (also reference etc.)
using std::begin;
using value_type = typename Container::value_type;
value_type value = *begin(data);
...
}
请注意,您可能根本不需要存储元素的类型:
template <typename Container>
void MyFunc(Container& data)
{
using std::begin;
auto value = *begin(data);
...
}
如果您只想在 std 容器上工作(或具有类似模板参数的容器)- 请参阅 答案。
诀窍是命名模板的模板参数:
#include <vector>
#include <iostream>
#include <typeinfo>
template <
typename T ,
typename A,
template <typename = T, typename = A> class Container_t
>
void MyFunc(Container_t<T, A> &data) {
std::cout << "value type = " << typeid(T).name() << std::endl;
std::cout << "allocator type = " << typeid(A).name() << std::endl;
std::cout << "container type = " << typeid(Container_t<T,A>).name() << std::endl;
}
template <typename T>
void MyFunc2( T v ) { }
int main()
{
std::vector<char> v;
MyFunc<char, std::allocator<char>, std::vector>(v); // OK
MyFunc(v); // now ok
}
如果除了值类型和容器你什么都不关心...
#include <vector>
#include <map>
#include <iostream>
#include <typeinfo>
template <
typename T ,
typename...Rest,
template <typename, typename...> class Container_t
>
void MyFunc(Container_t<T, Rest...> &data) {
std::cout << "value type = " << typeid(T).name() << std::endl;
std::cout << "container type = " << typeid(Container_t<T,Rest...>).name() << std::endl;
}
template <typename T>
void MyFunc2( T v ) { }
int main()
{
std::vector<char> v;
std::map<char, int> m;
// MyFunc<char, std::allocator<char>, std::vector>(v); // OK
MyFunc(v); // now ok
MyFunc(m); // now ok
}
我猜这是一个 VC++ 错误,因为 GCC 和 CLANG 可以推断出输入模板参数。正如 KerrekSB 在评论中提出的那样,一个不那么痛苦的解决方法如下:
template<typename T, template<typename...> class Container_t, typename... Args>
void MyFunc(Container_t<T, Args...> &data) {
...
}
在 C++11/C++14 中,
template <
typename T ,
template <typename...> class Container_t
>
void MyFunc(Container_t<T> &data) { ... }
template <typename T>
void MyFunc2( T v ) { ... }
int main()
{
std::vector<char> v;
MyFunc<char, std::vector>(v); // OK
MyFunc(v); // error
int i;
MyFunc2<int>(i); // OK
MyFunc2(i); // OK
}
我在 MyFunc(v)
中遇到错误。
有没有办法让编译器找出传递给可变参数模板函数的容器类型?我发现找到它没有问题,就像普通模板中的普通类型一样。
如果我需要更改 v 的类型,是否必须修复对 MyFunc 的所有调用?
编译器:Microsoft Visual C++ 2015 (v140)
与其尝试推断容器类型,不如假设容器定义了它存储的类型。
template <typename Container>
void MyFunc(Container& data)
{
// all std containers defines value_type member (also reference etc.)
using std::begin;
using value_type = typename Container::value_type;
value_type value = *begin(data);
...
}
请注意,您可能根本不需要存储元素的类型:
template <typename Container>
void MyFunc(Container& data)
{
using std::begin;
auto value = *begin(data);
...
}
如果您只想在 std 容器上工作(或具有类似模板参数的容器)- 请参阅
诀窍是命名模板的模板参数:
#include <vector>
#include <iostream>
#include <typeinfo>
template <
typename T ,
typename A,
template <typename = T, typename = A> class Container_t
>
void MyFunc(Container_t<T, A> &data) {
std::cout << "value type = " << typeid(T).name() << std::endl;
std::cout << "allocator type = " << typeid(A).name() << std::endl;
std::cout << "container type = " << typeid(Container_t<T,A>).name() << std::endl;
}
template <typename T>
void MyFunc2( T v ) { }
int main()
{
std::vector<char> v;
MyFunc<char, std::allocator<char>, std::vector>(v); // OK
MyFunc(v); // now ok
}
如果除了值类型和容器你什么都不关心...
#include <vector>
#include <map>
#include <iostream>
#include <typeinfo>
template <
typename T ,
typename...Rest,
template <typename, typename...> class Container_t
>
void MyFunc(Container_t<T, Rest...> &data) {
std::cout << "value type = " << typeid(T).name() << std::endl;
std::cout << "container type = " << typeid(Container_t<T,Rest...>).name() << std::endl;
}
template <typename T>
void MyFunc2( T v ) { }
int main()
{
std::vector<char> v;
std::map<char, int> m;
// MyFunc<char, std::allocator<char>, std::vector>(v); // OK
MyFunc(v); // now ok
MyFunc(m); // now ok
}
我猜这是一个 VC++ 错误,因为 GCC 和 CLANG 可以推断出输入模板参数。正如 KerrekSB 在评论中提出的那样,一个不那么痛苦的解决方法如下:
template<typename T, template<typename...> class Container_t, typename... Args>
void MyFunc(Container_t<T, Args...> &data) {
...
}