0

Scenario

  1. I have a class template:

    template<class idxT>
    class SimpleGraph {
    private:
      // ...
      std::set<std::pair<idxT,idxT>> edgeSet;
      // ...
      void addEdge(idxT a, idxT b);
      // ...
    }
    
  2. I need to use the return of edgeSet.emplace(a,b) inside addEdge(), which is denoted as r in the following.
  3. The declaration and the assignment of r need to be separated since the value of a and b is determined by a if-else statement. Thus, I cannot use

    auto r = edgeSet.emplace(a,b);
    
  4. I tried the following strategies but neither is successful. The first one is

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

    The second one is

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

Question

How can I declare the return of edgeSet.emplace(a,b)?

Update 1: a verifiable example for the first trial

#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 complains that

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;

See also here for the compile-time error generated by gcc.

Eli4ph
  • 307
  • 1
  • 13
  • 2
    Can't reproduce, both solutions [work for me](http://coliru.stacked-crooked.com/a/ca276bdbef42bab0). Can you show us the exact error message, and a [mcve] that reproduces your problem? – HolyBlackCat May 26 '18 at 10:40
  • Regarding point 3: I do not see how the presence of an if-else statement prevents the use of `auto` after the statement, nor why the if-else statement could not be relegated to a separate function. Perhaps the requested minimal, complete, and verifiable example should include an if-else demonstrating this? – JaMiT May 26 '18 at 11:06
  • @HolyBlackCat Thx. A verifiable example is added. – Eli4ph May 26 '18 at 11:44
  • And what do you mean by "not successful"? If you get compiler errors, please paste those as well. – aschepler May 26 '18 at 11:46
  • 1
    And what happens if you take the compiler's advice and add the `typename` keyword immediately before `decltype`? – G.M. May 26 '18 at 12:20

1 Answers1

1

The clang++ compiler is actually hinting at the solution with "did you forget 'typename'?"

Since decltype(edgeSet) is type-dependent (it indirectly depends on template parameter idxT), a compiler can't just look it up when it first parses the template, so C++ says to assume any name following decltype(edgeSet):: is a variable or function. Since it's really a type, you need to tell C++ so, using the keyword typename:

std::pair<typename decltype(edgeSet)::iterator,bool> r;

More details are at the answers to the question Where and why do I have to put the “template” and “typename” keywords?

Or, note that any valid expression at all can be used inside decltype. (And it's an unevaluated context, meaning that if you use function calls, implicit conversions, etc. no functions will actually be called for that expression.) So you could also just do:

decltype(edgeSet.emplace(a,b)) r;
aschepler
  • 65,919
  • 8
  • 93
  • 144
  • Thanks. Also, I find these two concepts—[static members](http://en.cppreference.com/w/cpp/language/static) and [dependent names](https://en.cppreference.com/w/cpp/language/dependent_name)—are helpful. – Eli4ph May 26 '18 at 19:27