如何声明实例化`std :: set`的`emplace()`的返回?

时间:2018-05-26 10:29:13

标签: c++ c++11 stl

方案

  1. 我有一个课程模板:

    template<class idxT>
    class SimpleGraph {
    private:
      // ...
      std::set<std::pair<idxT,idxT>> edgeSet;
      // ...
      void addEdge(idxT a, idxT b);
      // ...
    }
    
  2. 我需要在edgeSet.emplace(a,b)内使用addEdge()的返回值,以下表示为r
  3. r的声明和分配需要分开,因为ab的值由if-else语句决定。因此,我不能使用

    auto r = edgeSet.emplace(a,b);
    
  4. 我尝试了以下策略,但都没有成功。第一个是

    std::pair<decltype(edgeSet)::iterator,bool> r;
    // some code
    r = edgeSet.emplace(a,b);
    

    第二个是

    // inside class template
    typedef std::set<std::pair<idxT,idxT>> EdgeSetType;
    EdgeSetType edgeSet;
    
    // inside definition of `addEdge()`
    std::pair<EdgeSetType::iterator,bool> r;
    // some code
    r = edgeSet.emplace(a,b);
    
  5. 问题

    如何声明edgeSet.emplace(a,b)的返回?

    更新1:第一次试用的可验证示例

    #include <set>      // set
    #include <utility>  // pair
    #include <iostream>
    
    template<class idxT>
    class SimpleGraph {
    public:
      void test(void);
    
    private:
      std::set<std::pair<idxT,idxT>> edgeSet;
      void addEdge(idxT a, idxT b);
    };
    
    template<class idxT>
    void SimpleGraph<idxT>::test(void) {
      addEdge(1,2);
      addEdge(1,2);
    }
    
    template<class idxT>
    void SimpleGraph<idxT>::addEdge(idxT a, idxT b) {
    
      std::pair<decltype(edgeSet)::iterator,bool> r;
    
      if (a < b) {
        r = edgeSet.emplace(a,b);
      }
      else {
        r = edgeSet.emplace(a,b);
      }
      if (!r.second) {
        std::cerr << "Error on (" << a << ',' << b <<"): "
                  << "mutiple edges are not allowed for a simple graph.\n";
        exit(1);
      }
    }
    
    int main(void) {
      SimpleGraph<int> graph;
      graph.test();
    }
    

    clang抱怨说

    test.cpp:24:13: error: template argument for template type parameter must be a type; did you forget 'typename'?
      std::pair<decltype(edgeSet)::iterator,bool> r;
    

    另请参阅here了解gcc生成的编译时错误。

1 个答案:

答案 0 :(得分:1)

clang ++编译器实际上暗示了解决方案“你忘了'typename'吗?”

由于decltype(edgeSet)依赖于类型(它间接依赖于模板参数idxT),因此编译器在首次解析模板时不能只查找它,因此C ++会假设任何名称以下decltype(edgeSet)::是变量或函数。因为它实际上是一种类型,所以你需要使用关键字typename

告诉C ++
std::pair<typename decltype(edgeSet)::iterator,bool> r;

更多详细信息请参阅问题Where and why do I have to put the “template” and “typename” keywords?

的答案

或者,请注意,任何有效的表达式都可以在decltype中使用。 (这是一个未评估的上下文,这意味着如果你使用函数调用,隐式转换等,实际上不会为该表达式调用任何函数。)所以你也可以这样做:

decltype(edgeSet.emplace(a,b)) r;