Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Public "using" = decltype(<private>)

In the following (minimized) code, I have a public using declaration that is referring to decltype(something_private): using Foo = decltype(something_private<T>).

On Clang but not GCC this does not compile because of it being private.

Questions:

  1. What is an elegant solution if I do not want to make func<T>() public.
  2. Where in the C++ standard (C++11) does is backup Clang to be correct here?

The below code fails with the following error code on Clang (3.9 - 7.0) but builds on GCC (4.8.4 - 8.2):

class A {
private:
    template <class T>
    static auto func() -> T; // The actual return type is much
       // more complicated, so `using Foo = T` would not work.

public:
    template <class T>
    using Foo = decltype(func<T>());
};

int main(int, char**) {
    A::Foo<int> y;
    return y;
}

Clang 7.0 output:

<source>:10:24: error: 'func' is a private member of 'A'
  using Foo = decltype(func<T>());
                       ^~~~~~~

<source>:14:7: note: in instantiation of template type alias 'Foo' requested here
   A::Foo<int> y;
          ^

<source>:6:15: note: declared private here
  static auto func() -> T;
              ^

1 error generated.
Compiler returned: 1

https://godbolt.org/z/zD4Hk5

like image 373
Unapiedra Avatar asked Oct 19 '18 01:10

Unapiedra


1 Answers

I haven't looked in the standard for citation, but have a workaround for you. Because this works, it makes me think clang just has a bug. When the function is directly in A, it treats the type alias as if it were in the context of the caller, but moving the function into a struct solves that. Meh. I've done a lot of g++ / clang porting lately and while I didn't run into this specifically, it smelled of some things I encountered.

class A {
private:
  struct X {
    template <class T>
    static auto func() -> T;
  };

public:
  template <class T>
  using Foo = decltype(X::func<T>());
};

void bar() {
   A::Foo<int> y;
}

https://godbolt.org/z/ozIS-r

UPDATE: added citation.

I think this directly answers your question, and that clang is wrong here.

N4778 (the latest I found), 10.8/p4 (pg 259) ... [Note: Because access control applies to names, if access control is applied to a typedef name, only the accessibility of the typedef name itself is considered. The accessibility of the entity referred to by the typedef is not considered.

like image 95
Chris Uzdavinis Avatar answered Nov 12 '22 10:11

Chris Uzdavinis