Search code examples
c++c++11templateslanguage-lawyerdecltype

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


Solution

  • I haven't looked at 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.