Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it legal to define a hidden friend in an explicit specialization of an otherwise non-defined member class of a class template?

The rules for legal placement of explicit specializations as per [temp.expl.spec] are not entirely easy to grasp, particularly when mixing with hidden friends, so as to avoid the immolation[temp.expl.spec]/8 of my specializations and friend functions I wish a second opinion(1) on the following:

  • Is it legal to define, in a header file of a class template, a hidden friend in an explicit specialization of an otherwise non-defined (/only declared) member class of the class template? Assume that this header is included in at least two different translation units.

(1) My own interpretation of the standard says that the answer is "yes; this is legal", as per the standard references below.


Or, with an example: is the following program well-formed?

// s.h
#pragma once

template <int N>
struct S {
    struct M;
};
      
template<>
struct S<42>::M {
    friend int f(M) { return 42; }
};

// foo.h
#pragma once
void foo();

// foo.cpp
#include "foo.h"
#include <iostream>
#include "s.h"

void foo() {
    std::cout << f(S<42>::M{});
}

// main.cpp
#include <iostream>
#include "foo.h"
#include "s.h"

int main() {
    std::cout << f(S<42>::M{});
    foo();
}

Note that friends defined at their friend declarations are inline as per [class.friend]/7, so whilst I'm somewhat worried about ODR-violations it is not for the friend but rather for the member class specialization. I think [basic.def.odr]/6 applies here if we consider S<42>::M as "just" a class type.


Clang and GCC both accepts the above, but this may not be significant in case the program is ill-formed NDR or has undefined behaviour. GCC 10.1.0 DEMO, Clang 10.0.0 DEMO.

like image 935
dfrib Avatar asked Nov 07 '22 04:11

dfrib


1 Answers

Yes, an explicit specialization of a templated class (which includes class templates and member classes of class templates) is a class, and so multiple definitions are allowed under the usual circumstances. Those definitions are treated as if there were but one in the program, so f is OK as well. (It’s not clear that implicit inline does anything here, since there is only one definition of f to the extent that there is only one of S<42>::M as a whole.) Neither does the lack of definition for S<N>::M mean anything here; a “member explicit specialization” like this is really an abbreviated specialization of the enclosing class template S, so S<42>::M is quite unrelated.

like image 81
Davis Herring Avatar answered Nov 15 '22 01:11

Davis Herring