Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ error: was not declared in this scope with private after public

Attempting to modify the code from this page.

Here's the problem code:

#include <iostream>
#include <array>

template<class T>
class const_reverse_wrapper
{
public:
    const_reverse_wrapper (const T& cont)
        : container_(cont)
    {
    }

    decltype( container_.rbegin() ) begin() const
    {
        return container_.rbegin();
    }

    decltype( container_.rend() ) end()
    {
        return container_.rend();
    }

private:
    const T & container_;
};

template<class T>
class reverse_wrapper
{
public:
    reverse_wrapper (T & cont)
        : container_(cont)
    {
    }

    decltype( container_.rbegin() ) begin()
    {
        return container_.rbegin();
    }

    decltype( container_.rend() ) end()
    {
        return container_.rend();
    }
private:
    T & container_;
};

template<class T>
const_reverse_wrapper<T> reversed (const T & cont)
{
    return const_reverse_wrapper<T>(cont);
}

template<class T>
reverse_wrapper<T> reverse (T & cont)
{
    return reverse_wrapper<T>(cont);
}

int main (int argc, char * argv[])
{
    std::array<int,4> a = { 1, 2, 3, 4 };
    for (int i : a)
        std::cout << i;
    return 0;
}

When I compile it, I get these errors:

> g++ -std=c++0x test2.cpp
test2.cpp:13:15: error: 'container_' was not declared in this scope
test2.cpp:13:15: error: 'container_' was not declared in this scope
test2.cpp:18:15: error: 'container_' was not declared in this scope
test2.cpp:18:15: error: 'container_' was not declared in this scope
test2.cpp:36:15: error: 'container_' was not declared in this scope
test2.cpp:36:15: error: 'container_' was not declared in this scope
test2.cpp:41:15: error: 'container_' was not declared in this scope
test2.cpp:41:15: error: 'container_' was not declared in this scope

When I move the private sections before the public sections in each class, the errors go away.

template<class T>
class const_reverse_wrapper
{
private:                    // <-----
    const T & container_;   // <-----
public:
    const_reverse_wrapper (const T& cont)
        : container_(cont)
    {
    }

    decltype( container_.rbegin() ) begin() const
    {
        return container_.rbegin();
    }

    decltype( container_.rend() ) end()
    {
        return container_.rend();
    }
};

template<class T>
class reverse_wrapper
{
private:              // <-----
    T & container_;   // <-----
public:
    reverse_wrapper (T & cont)
        : container_(cont)
    {
    }

    decltype( container_.rbegin() ) begin()
    {
        return container_.rbegin();
    }

    decltype( container_.rend() ) end()
    {
        return container_.rend();
    }
};

I've tried compiling with MinGW GCC 4.6.2 and 4.7.0 and get the same results. Is this a bug, or is there something else going on?

like image 475
user1594322 Avatar asked Nov 05 '12 04:11

user1594322


1 Answers

You had the same problem before C++11:

struct X{
  Foo f(){ return 42; } // error: 'Foo' does not name a type

  typedef int Foo;
};

The reason for this is that only the body of a member function is treated as if it was defined out-of-class with regards to member availability.

§9.2 [class.mem] p2

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

As such, only names previously seen inside of the class member-specification (as the standard calls it) can be used.

I see two possible fixes, one for your specific use-case and a general one. For your specific case, just use typename T::const_reverse_iterator. For the general case, use std::declval to obtain an object of a certain type for decltype and call the method on that:

#include <functional>

decltype(std::declval<T const&>().rbegin()) rbegin() const{ ... }
like image 193
Xeo Avatar answered Sep 30 '22 00:09

Xeo