templateclass类型的模板功能如何实现?
How to realize template class type in template function?
我想为STL容器设计一个打印功能,包括:std::vector, std::map, std::unodered_map, std::set, std::unordered_set, std::list
....
理想的函数如下所示:
template<typename T>
void Show(const T& t)
{
if (istype(t, std::vector))
{
// here is a presudo code
// print vector
for (auto i: t) cout << i << endl;
}
else if (istype(t, std::unordered_map))
{
// print unordered_map
}
else
{ }
}
我认为问题发生在 istype()
我知道有一些像 std::is_same
这样的函数可以做到这一点。
但是好像只能在int
或[=16=上操作,不能在std::vector
上操作,你能帮忙吗?
所有 STL 容器的共同特征是它们在 [begin(),end())
范围内是可迭代的。对于序列容器,您必须将打印 T
处理为 value_type,对于(无序)关联容器,打印 std::pair<const Key, T>
必须处理为 value_type。就这些。我看不出有任何理由在您的实施中检查传递的容器类型。
template<class T>
void Print(const T& val) {
std::cout << val;
}
template<class Key, class Value>
void Print(const std::pair<const Key,Value>& p) {
Print(p.first);
std::cout << " - ";
Print(p.second);
}
template<class Cont>
void PrintCont(const Cont& cont) {
std::cout << std::endl;
for (auto it = cont.begin(); it != cont.end(); ++it) {
Print(*it);
std::cout << " ";
}
std::cout << std::endl;
}
std::array<int,2> a{1,2};
std::vector<int> v{1,2,3};
std::list<double> l{2., 3., 5.4};
std::map<int,double> m{ {1,2.},{10,3.14} };
std::multimap<int,int> m2{ {2,3},{4,5} };
std::set<float> s{1.f, 23.f, 2.f};
std::unordered_map<int,Foo> m3{ {1,Foo(1)}, {2,Foo(2)}, {3,Foo(3)}};
PrintCont(a);
PrintCont(v);
PrintCont(l);
PrintCont(m);
PrintCont(a);
PrintCont(s);
PrintCont(m2);
PrintCont(m3);
But it seems it just can operate on int
or float
, cant be operated
on std::vector
, can you help on this?
对于像搁浅容器这样的模板类,您需要指定模板参数以获取具体类型,然后您可以使用std::is_same
进行比较。这意味着像 std::is_same_v<T, std::vector<int>>
或 std::is_same_v<T, std::vector<float>>
等... 将起作用。
另一方面,您需要查看传递的容器是否是标准容器的特化。你需要自己的 std::is_same_v
类型特征。
一种可能的实现如下所示。另请注意,您需要使用 (since c++17) instead of normal if
for compile time branching. If no access to c++17, you need to use SFINAE.
#include <iostream>
#include <type_traits> // std::false_type, std::true_type
#include <vector>
#include <list>
#include <string>
#include <map>
template<typename Type, template<typename...> class Args>
struct is_specialization final : std::false_type {};
template<template<typename...> class Type, typename... Args>
struct is_specialization<Type<Args...>, Type> : std::true_type {};
template<typename ContainerType>
constexpr void show(const ContainerType& container) noexcept
{
if constexpr (is_specialization<ContainerType, std::vector>::value
|| is_specialization<ContainerType, std::list>::value)
{
for (const auto ele : container)
std::cout << ele << '\t';
std::cout << '\n';
}
else if constexpr (is_specialization<ContainerType, std::map>::value)
{
for (const auto& [key, value]: container)
std::cout << key << " " << value << '\t';
std::cout << '\n';
}
// ... so on!
}
int main()
{
std::vector<int> vec{ 1, 2, 3 };
show(vec);
std::list<int> list{ 11, 22, 33 };
show(list);
std::map<int, std::string> mp{ {1, "string1"}, {2, "string2"}, {3, "string3"} };
show(mp);
}
我想为STL容器设计一个打印功能,包括:std::vector, std::map, std::unodered_map, std::set, std::unordered_set, std::list
....
理想的函数如下所示:
template<typename T>
void Show(const T& t)
{
if (istype(t, std::vector))
{
// here is a presudo code
// print vector
for (auto i: t) cout << i << endl;
}
else if (istype(t, std::unordered_map))
{
// print unordered_map
}
else
{ }
}
我认为问题发生在 istype()
我知道有一些像 std::is_same
这样的函数可以做到这一点。
但是好像只能在int
或[=16=上操作,不能在std::vector
上操作,你能帮忙吗?
所有 STL 容器的共同特征是它们在 [begin(),end())
范围内是可迭代的。对于序列容器,您必须将打印 T
处理为 value_type,对于(无序)关联容器,打印 std::pair<const Key, T>
必须处理为 value_type。就这些。我看不出有任何理由在您的实施中检查传递的容器类型。
template<class T>
void Print(const T& val) {
std::cout << val;
}
template<class Key, class Value>
void Print(const std::pair<const Key,Value>& p) {
Print(p.first);
std::cout << " - ";
Print(p.second);
}
template<class Cont>
void PrintCont(const Cont& cont) {
std::cout << std::endl;
for (auto it = cont.begin(); it != cont.end(); ++it) {
Print(*it);
std::cout << " ";
}
std::cout << std::endl;
}
std::array<int,2> a{1,2};
std::vector<int> v{1,2,3};
std::list<double> l{2., 3., 5.4};
std::map<int,double> m{ {1,2.},{10,3.14} };
std::multimap<int,int> m2{ {2,3},{4,5} };
std::set<float> s{1.f, 23.f, 2.f};
std::unordered_map<int,Foo> m3{ {1,Foo(1)}, {2,Foo(2)}, {3,Foo(3)}};
PrintCont(a);
PrintCont(v);
PrintCont(l);
PrintCont(m);
PrintCont(a);
PrintCont(s);
PrintCont(m2);
PrintCont(m3);
But it seems it just can operate on
int
orfloat
, cant be operated onstd::vector
, can you help on this?
对于像搁浅容器这样的模板类,您需要指定模板参数以获取具体类型,然后您可以使用std::is_same
进行比较。这意味着像 std::is_same_v<T, std::vector<int>>
或 std::is_same_v<T, std::vector<float>>
等... 将起作用。
另一方面,您需要查看传递的容器是否是标准容器的特化。你需要自己的 std::is_same_v
类型特征。
一种可能的实现如下所示。另请注意,您需要使用 if
for compile time branching. If no access to c++17, you need to use SFINAE.
#include <iostream>
#include <type_traits> // std::false_type, std::true_type
#include <vector>
#include <list>
#include <string>
#include <map>
template<typename Type, template<typename...> class Args>
struct is_specialization final : std::false_type {};
template<template<typename...> class Type, typename... Args>
struct is_specialization<Type<Args...>, Type> : std::true_type {};
template<typename ContainerType>
constexpr void show(const ContainerType& container) noexcept
{
if constexpr (is_specialization<ContainerType, std::vector>::value
|| is_specialization<ContainerType, std::list>::value)
{
for (const auto ele : container)
std::cout << ele << '\t';
std::cout << '\n';
}
else if constexpr (is_specialization<ContainerType, std::map>::value)
{
for (const auto& [key, value]: container)
std::cout << key << " " << value << '\t';
std::cout << '\n';
}
// ... so on!
}
int main()
{
std::vector<int> vec{ 1, 2, 3 };
show(vec);
std::list<int> list{ 11, 22, 33 };
show(list);
std::map<int, std::string> mp{ {1, "string1"}, {2, "string2"}, {3, "string3"} };
show(mp);
}