1

Background

I'm trying to write a container which will contain iterators. E.g. it creates indirection range. I want the iterator of the range to dereference underlying iterator. I did that, but then I need relational operators. Here is the reduced version that reproduces the problem:

mcve

template <typename T>
struct foo
{
    class bar
    {
        friend bool do_something(bar);
    };

    bar get_bar()
    {
        return bar{};
    }
};

template <typename T>
bool do_something(typename foo<T>::bar)
{
    return true;
}

#include <iostream>

int main()
{
    foo<int> f;
    auto b = f.get_bar();
    std::cout << do_something(b);
}

/tmp/prog-c08a3a.o: In function main': prog.cc:(.text+0x12): undefined reference todo_something(foo::bar)'

demo on wandbox.

This is the only error I get.

Question

What is declared inside of the class and what is defined as free function outside of the class?

What I tried

Compiler asks me to put a template, but that is clearly not what I want. I don't want my iterator related to one ForwardIterator type to be comparable to iterator of another ForwardIterator type. But I thought ok, lets try that, but it gave me shadowing error, which strengthened my suspicions.

Reasons why I want to define inside

From what I've heard, defining it inside will make it only ADL callable. Some IDEs might not figure that out, so I thought that declaring them outside is better.

Incomputable
  • 2,188
  • 1
  • 20
  • 40

1 Answers1

5

The simpler would be to define the function directly in the class:

template <typename T>
struct foo
{
    class bar
    {
        friend bool do_something(bar) { /* implementation */}
    };

    bar get_bar()
    {
        return bar{};
    }
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I guess users should file a bug report against their IDEs then. Fixing it on the code side seems to bring quite a lot of a hassle. – Incomputable Feb 01 '18 at 12:54
  • You don't have real good alternatives, in `template bool do_something(typename foo::bar)`, `T` is non deducible. – Jarod42 Feb 01 '18 at 12:57
  • @Jarod42 On top of that, the `do_something` in this answer *is not a template function*, but a non-template friend of a non-template class contained in a template struct. – Yakk - Adam Nevraumont Feb 02 '18 at 12:41