Constexpr is not allowed in declaration of friend template specialization?

119 views
Skip to first unread message

rhalb...@gmail.com

unread,
Apr 28, 2015, 9:30:38 AM4/28/15
to std-dis...@isocpp.org
Taken from this StackOverflow Q&A

#include <cstddef>

template<std::size_t>
class bitset;

template<std::size_t N>
constexpr bool operator==(const bitset<N>&, const bitset<N>&) noexcept;

template<std::size_t N>
class bitset
{
    friend constexpr bool operator== <>(const bitset<N>&, const bitset<N>&) noexcept;
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- error from this piece
};

template<std::size_t N>
constexpr bool operator==(const bitset<N>&, const bitset<N>&) noexcept
{
    return true;
}

int main() {}
Clang compiles this code just fine (in c++11 mode, and has been since at least clang 3.3). However, g++ (4.8 nor 5.1) does not (it even has a dedicated unit test against it). Its error message
 
'constexpr' is not allowed in declaration of friend template specialization
 
seems to be a conflict between [dcl.constexpr]/2 (constexpr functions are implicitly inline) and [temp.friend]/9 (the inline specifier shall not be used in the declaration of a specialization of a function template). It would be rather annoying if completely idiomatic use of operator overloading is not possible in combination with the constexpr keyword. Furthermore, I find it hard to believe that an implicit inline is equivalent to the inline specifier (the implication should only run from the latter to the former, not the other way around) 

So who's right: clang or g++? Or should I file a DR for the core langauge?

David Krauss

unread,
Apr 28, 2015, 10:24:54 AM4/28/15
to std-dis...@isocpp.org
On 2015–04–28, at 9:30 PM, rhalb...@gmail.com wrote:

seems to be a conflict between [dcl.constexpr]/2 (constexpr functions are implicitly inline) and [temp.friend]/9 (the inline specifier shall not be used in the declaration of a specialization of a function template). It would be rather annoying if completely idiomatic use of operator overloading is not possible in combination with the constexpr keyword. Furthermore, I find it hard to believe that an implicit inline is equivalent to the inline specifier (the implication should only run from the latter to the former, not the other way around) 

It’s not by implication. GCC is specifically diagnosing this condition. cp/decl.c:7749:

  if (inlinep & 2)
    error ("%<constexpr%> is not allowed in declaration of friend "
   "template specialization %qD",

So who's right: clang or g++? Or should I file a DR for the core langauge?

The standard doesn’t seem to support GCC here. File a bug, even if the standard is wrong.

As for the core language, note that both Clang and GCC accept your program if you remove the constexpr keyword. I think the prohibition on inline is based on the idea of separation of concerns. A friend declaration shouldn’t need to be aware of details like whether or not the function is inline or constexpr. This only adds brittleness. It’s even impossible, per the standard, to befriend a specialization that may or may not be constexpr depending on the class template parameters.

The rule requiring constexpr on the declaration ([dcl.constexpr] §7.1.5/1) should be removed. Even better, [temp.friend] §14.5.4/1 should clarify that such a declaration that refers to a preexisting function, does not count as a redeclaration of it for the sake of such semantic checks.
Reply all
Reply to author
Forward
0 new messages