dimanche 23 août 2015

Declaring a constexpr specialization as friend

I have a templated class A and a templated function f which returns A objects. I want f<T> to be a friend of A<T> and still be constexpr

template <typename T>
class A;

template <typename T>
constexpr A<T> f();

//f<T> is a friend of A<T>

template <typename T>
class A {
  friend /* constexpr? */ A f<T>();
  constexpr A() {}
};

template <typename T>
constexpr A<T> f() { return {}; }

int main() {
  constexpr auto a  = f<void>();
}

I can't get clang and gcc to agree on what's right here. If I don't put constexpr in the friend declaration, gcc works fine but clang won't compile it, erroring with:

main.cpp:18:18: error: constexpr variable 'a' must be initialized by a constant expression
  constexpr auto a  = f<void>();
                 ^    ~~~~~~~~~
main.cpp:18:23: note: non-constexpr function 'f<void>' cannot be used in a constant expression
  constexpr auto a  = f<void>();
                      ^
main.cpp:9:12: note: declared here
  friend A f<T>(); 

If I mark it as constexpr in the friend declaration, clang compiles fine but gcc gives me the error:

main.cpp:9:27: error: 'constexpr' is not allowed in declaration of friend template specialization 'A<T> f<T>()'
   friend constexpr A f<T>();

How can I make everyone happy?

Note that I want to restrict this to a specialization. I know I can do

template <typename> friend constexpr A f();

Aucun commentaire:

Enregistrer un commentaire