简体   繁体   English

如何在模板函数中实现模板类类型?

[英]How to realize template class type in template function?

I want to design a print function for STL container, include: std::vector, std::map, std::unodered_map, std::set, std::unordered_set, std::list ....我想为 STL 容器设计一个打印函数,包括: std::vector, std::map, std::unodered_map, std::set, std::unordered_set, std::list ....

The ideal function looks like:理想的函数如下所示:

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 
    {  }
}

I think the problem happens on istype()我认为问题发生在istype()

I know there is some function like std::is_same can do this.我知道有一些像std::is_same这样的函数可以做到这一点。

But it seems it just can operate on int or float , cant be operated on std::vector , can you help on this?但它似乎只能在intfloat上操作,不能在std::vector ,你能帮忙吗?

Common feature of all STL containers is that they are iterable in range [begin(),end()) .所有 STL 容器的共同特点是它们在[begin(),end())范围内可迭代。 For sequence containers you have to handle printing T as value_type, for (Unordered) associative containers printing std::pair<const Key, T> as value_type must be handled.对于序列容器,您必须将T打印为 value_type,对于(无序)关联容器std::pair<const Key, T>必须处理将std::pair<const Key, T>打印为 value_type。 That is all.就这些。 I don't see any reasons to checking type of passed container in your implemention.我看不出有任何理由在您的实现中检查传递的容器的类型。

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);

Live demo现场演示

But it seems it just can operate on int or float , cant be operated on std::vector , can you help on this?但它似乎只能在intfloat上操作,不能在std::vector ,你能帮忙吗?

For template classes like stranded containers, you need to specify the template argument to get the concrete type and thereafter you can compare using std::is_same .对于像搁浅容器这样的模板类,您需要指定模板参数以获取具体类型,然后您可以使用std::is_same进行比较。 That means something like std::is_same_v<T, std::vector<int>> or std::is_same_v<T, std::vector<float>> , etc... will work.这意味着像std::is_same_v<T, std::vector<int>>std::is_same_v<T, std::vector<float>> ......会起作用。

On the other side, you need to see whether the passed container is a specialization for the standard container.另一方面,您需要查看传递的容器是否是标准容器的特化。 There you need your own std::is_same_v like type traits.在那里你需要你自己的std::is_same_v类型特征。

One possible implementation will look like as follows.一种可能的实现如下所示。 Also note that you need to use the if constexpr (since ) instead of normal if for compile time branching.另请注意,对于编译时分支,您需要使用if constexpr (自)而不是正常的if If no access to , you need to use SFINAE .如果无法访问 ,则需要使用SFINAE

( See a Demo ) 见演示

#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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM