简体   繁体   中英

explicit template specialization with no explicit specialization declaration

I have small example code:

file foo.h:

#pragma once

template <typename T> class FooNoDef {
public:
  void foo(const T& value); // declared and not defined
};

class FooUser {
public:
  template <typename T> static void useFoo(const T& value) {
    FooNoDef<T>{}.foo(value);
  }
};

file xy.h:

#pragma once

struct X {};
struct Y {};

file xy.cpp:

#include "foo.h"
#include "xy.h"
#include <iostream>

template <> void FooNoDef<X>::foo(const X& value) {
  std::cout << "x" << std::endl;
}

template <> void FooNoDef<Y>::foo(const Y& value) {
  std::cout << "y" << std::endl;
}

and finally main.cpp:

#include "foo.h"
#include "xy.h"

int main() {
  FooUser::useFoo(X{});
  FooUser::useFoo(Y{});
  return 0;
}

This code compiles with gcc 11 and clang 13. I suspect my code is ill-formed, but I can't find a definite answer from reading the standard:

Section 13.9.4 [temp.expl.spec] (emphasis mine):

If a template, a member template or a member of a class template is explicitly specialized, a declaration of that specialization shall be reachable from every use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.

Section 13.9.2 [temp.inst] (emphasis mine):

[Example 5:

template<class T> struct Z {
  void f();
  void g();
};

void h() {
  Z<int> a;         // instantiation of class Z<int> required
  Z<char>* p;       // instantiation of class Z<char> not required
  Z<double>* q;     // instantiation of class Z<double> not required

  a.f();            // instantiation of Z<int>​::​f() required
  p->g();           // instantiation of class Z<char> required, and
                    // instantiation of Z<char>​::​g() required
}

Nothing in this example requires class Z, Z::g(), or Z::f() to be implicitly instantiated.** — end example]

I think FooUser::useFoo() does not cause implicit instantiation of FooNoDef::foo() as the example from the standard discussed, but still I never provided a declaration for my explicit specialization of FooNoDef<X> and FooNoDef<Y> . Which rule of C++, if any, do I violate with my example? Would I have to provide explicit specialization declaration template <> void FooNoDef<X>; and template <> void FooNoDef<Y>; strictly before the body of FooUser::useFoo() ?

As far as I can see, you are right, though you've put emphasise on the wrong line of the standard:

[...] a declaration of that specialization shall be reachable from every use of that specialization [...]

Within main , both of FooUser::useFoo<X> and FooUser::useFoo<Y> need to be instantiated. These then need to instantiate FooNoDef<X>::foo and FooNoDef<Y>::foo – and here an implicit instantiation would be caused, if no explicit instantiation was available.

However, there only exists a definition within xy.cpp , and that's not visible to main.cpp , and there's no visible declaration – violating above cited phrase, thus your programme indeed is ill-formed.

To fix, you'd need to add a declaration, eg in xy.h (note: the header that is included by main.cpp ):

template <> void FooNoDef<X>::foo(X const& value);
template <> void FooNoDef<Y>::foo(Y const& value);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM