代码之家  ›  专栏  ›  技术社区  ›  PapaDiHatti

如果模板模板参数为vector,则需要不同的行为

  •  2
  • PapaDiHatti  · 技术社区  · 6 年前

    我们使用的是一个内部C++库。 std::vector 但是,作为输入,我希望编写能够接受的包装函数 STD::载体 , std::set std::unordered_set 但是当传递给这个包装函数的输入是 STD::载体 我不想在临时向量中复制它,所以有什么方法可以避免这种不必要的复制。

    示例参考代码将更清晰地解释此问题:

    #include <iostream>
    #include <set>
    #include <vector>
    #include <unordered_set>
    void print(const std::vector<int>& argVec)
    {
        for(auto elem:argVec)
        {
            std::cout<<elem<<std::endl;
        }
    
    }
    template<template<typename...>class VecOrSet>
    void wrapper(const VecOrSet<int>& input)
    {
        //How to avoid this temporary vector if input argument is vector itself
        std::vector<int> temp(input.begin(),input.end());
        print(temp);
    }
    int main()
    {
      std::vector<int> v{1,2,3};  
      std::set<int> s{4,5,6};
      std::unordered_set<int> us{7,8,9};
      wrapper(v);
      wrapper(s);
      wrapper(us);
      return 0;
    }
    
    2 回复  |  直到 6 年前
        1
  •  4
  •   songyuanyao    6 年前

    您可以添加 full specialization .

    template<>
    void wrapper(const std::vector<int>& input)
    {
        print(input);
    }
    

    或者只是添加另一个过载。

    void wrapper(const std::vector<int>& input)
    {
        print(input);
    }
    

    或使用 constexpr if (C++ 17)。

    template<template<typename...>class VecOrSet>
    void wrapper(const VecOrSet<int>& input)
    {
        if constexpr (std::is_same_v<VecOrSet<int>, std::vector<int>>) {
            print(input);
        } else {
            std::vector<int> temp(input.begin(),input.end());
            print(temp);
        }
    }
    
        2
  •  1
  •   max66    6 年前

    另一个解决方案可以初始化 temp 传递另一个函数: getIntVect() ,具有通用版本

    template <typename VoS>
    std::vector<int> getIntVect (VoS const & input)
     { return { input.cbegin(), input.cend() }; }
    

    那个复制品 input 在一个 std::vector<int> 和的特定版本 std::version<int>

    std::vector<int> const & getIntVect (std::vector<int> const & input)
     { return input; }
    

    返回对输入的常量引用(即:避免复制)

    所以,使用 decltype(auto) ,

    template<template<typename...>class VecOrSet>
    void wrapper(const VecOrSet<int>& input)
    {
       decltype(auto) temp { getIntVect(input) };
    
       print( temp );
    }
    

    临时雇员 是指 输入 VecOrSet std::vector 输入 ,否则。

    --编辑--

    手术是可疑的

    我想这条线 decltype(auto) temp{getIntVect(input)}; 如果输入为矢量,将调用矢量的复制构造函数

    这是真的 auto temp{getIntVect(input)}; 如T.C.所指(谢谢!).不适用于 decltype(auto)温度getintvect(input)

    尝试编译并运行以下代码

    #include <iostream>
    
    struct A
     {
       A ()
        { std::cout << "- default constructor" << std::endl; }
    
       A (A const &)
        { std::cout << "- copy constructor" << std::endl; }
    
       A (A &&)
        { std::cout << "- move constructor" << std::endl; }
     };
    
    template <typename T>
    A foo (T const &)
     { return {}; }
    
    A const & foo (A const & a)
     { return a; }
    
    int main ()
     {
       std::cout << "--- 000" << std::endl;
       A a0;
       std::cout << "--- 001" << std::endl;
       auto           a1 { foo(a0) };
       std::cout << "--- 002" << std::endl;
       decltype(auto) a2 { foo(a0) };
       std::cout << "--- 003" << std::endl;
       decltype(auto) a3 { foo(0) };
       std::cout << "--- 004" << std::endl;
     }
    

    我(从g++和clang++中)得到这个输出

    --- 000
    - default constructor
    --- 001
    - copy constructor
    --- 002
    --- 003
    - default constructor
    --- 004
    

    如你所见, auto a1 { foo(a0) }; 调用的复制构造函数 A auto A a1 { foo(a0) }; foo() decltype(auto) a2 { foo(a0) }; A const & A const & a2 { foo(a0) }; a2 foo(a0) a0