Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC allows access to private static member

Tags:

c++

gcc

clang

This code works on GCC but not clang.

class Base
{
    static constexpr int PRIVATE = 1;
};

struct Derived : public Base
{
    template <class T>
    int bar( T & t )
    {
        return PRIVATE;
    }
};

int main()
{
    Derived d;
    int i = 3;
    d.bar(i);
}

Godbolt link: https://godbolt.org/g/qPJ47p

In the case of a private member function, GCC correctly detects the attempt to access a private member if the template function is instantiated, but otherwise does not. Clang detects the attempt even when the template function is never instantiated.

However, when using a private static constexpr variable, GCC (up to the latest 8.1) fails to stop private access even if the template function is instantiated. Clang correctly (?) complains.

Question: which of the two compilers is Standard-compliant in this situation?

It seems to me that GCC can't be right in allowing access to a private static constexpr variable. Yet at the same time it doesn't seem like an overly complicated issue, but it isn't in the latest GCC: that makes it seem intentional.

Much thanks to paxdiablo for his clear and thorough answer. According to his suggestion I've made a more comprehensive list of test cases and narrowed it down to the static specifier causing the problem for GCC. See this Godbolt link for more detail: https://godbolt.org/g/A3zCLk

Comparison of GCC and Clang:

Private member    | GCC         | Clang

static const      | accept      | reject
static constexpr  | accept      | reject
static            | accept      | reject
const             | instantiate | reject
no-specifiers     | instantiate | reject
static function   | instantiate | reject
function          | instantiate | reject

("instantiate" means GCC rejects it upon template instantiation)
like image 788
Anton Avatar asked May 28 '18 02:05

Anton


People also ask

Can static members be private?

Static member variables It is essentially a global variable, but its name is contained inside a class scope, so it goes with the class instead of being known everywhere in the program. Such a member variable can be made private to a class, meaning that only member functions can access it.

How can we access a static member?

We can access the static member function using the class name or class' objects. If the static member function accesses any non-static data member or non-static member function, it throws an error. Here, the class_name is the name of the class. function_name: The function name is the name of the static member function.

Can we Create private static characteristics of class in c++?

It is possible to declare a data member of a class as static irrespective of it being a public or a private type in class definition. If a data is declared as static, then the static data is created and initialized only once.


1 Answers

This definitely looks like a bug since whether it's an instantiated template function or a real function should have no bearing on accessibility of private members in the base class. If you change your code to:

int bar(int&) {
    return PRIVATE;
}

then it rightly complains:

testprog.cpp: In member function 'int Derived::bar(int&)':
testprog.cpp:3:26: error: 'constexpr const int Base::PRIVATE' is private
     static constexpr int PRIVATE = 1;
                          ^
testprog.cpp:9:16: error: within this context
         return PRIVATE;
                ^

I would just raise this as a bug on gcc. If they do have a different view on its validity, they will let you know about it.

And, for when you do file the bug, I'd suggest using the absolute minimalist example that works, it'll make it much easier for them to debug. I got that down to:

class Base {
    static constexpr int PRIVATE = 42;
};
struct Derived : public Base {
    template <class T> int bar(T) {
        return PRIVATE;
    }
};
int main() {
    Derived d;
    return d.bar(1);
}

You may also want to indicate the various possibilities for declaring PRIVATE and their effect on gcc and clang (trunks as of this question):

                                gcc       clang
                              --------   --------
static constexpr int          accepted   rejected
static const int              accepted   rejected
const int                     rejected   rejected
int                           rejected   rejected

Using a non-templated function instead (as mentioned above):

int bar(int) {
    return PRIVATE;
}

seems to result in gcc "behaving" itself:

                                gcc       clang
                              --------   --------
static constexpr int          rejected   rejected
static const int              rejected   rejected
const int                     rejected   rejected
int                           rejected   rejected

So, if this is indeed a gcc problem, I'd be thinking that there's some interaction between static and templates which is causing the issue.

like image 103
paxdiablo Avatar answered Oct 31 '22 10:10

paxdiablo