5

According to https://eel.is/c++draft/temp.expl.spec#7:

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.

Therefore I wonder, is the following program ill-formed, NDR?

// foo.h
template <typename T>
void foo();

// Specialization not declared in the header!

// foo.cpp
#include "foo.h"

template <>
void foo<int>()
{
 // ...
}

// main.cpp
#include "foo.h"

int main()
{
    foo<int>();
}
user1011113
  • 1,114
  • 8
  • 27
  • 1
    It's interesting to note that had it been explicit instantiation instead, [the code would have been well formed](https://timsong-cpp.github.io/cppwp/n4868/temp#pre-10). I guess implementations are allowed to mangle explicit specializations differently. – StoryTeller - Unslander Monica Mar 03 '22 at 10:47
  • 7
    "shall" in the standard means "must" or "is required to". So you already have the answer in your quote of the standard. The explicit template specialization in `foo.cpp` has no declaration, that is reachable from the use in `main.cpp`. So yes it is ill formed. – Jakob Stark Mar 03 '22 at 10:48
  • An interesting variation is: what if we add an explicit instantiation _declaration_ of the `foo()` spec. after the declaration of the primary template in `foo.h`? It seems to be the reasonable thing to do to highlight that the instantiation definition shall not be implicitly instantiated. Or, formally, to highlight that there is in fact a _reachable_ explicit instantiation definition elsewhere, meaning the `foo()` is a _declared_ specialization and shouldn't be implicitly instantiated anywhere. However [\[temp.spec\]/5.3](https://timsong-cpp.github.io/cppwp/n4861/temp.spec#5.3) ... – dfrib Mar 03 '22 at 11:35
  • ... makes no different on explicit instantiation declarations/definitions when requiring _"both an **explicit instantiation** and a declaration of an explicit specialization shall not appear in a program **unless the explicit instantiation follows** a declaration of the explicit specialization."_. – dfrib Mar 03 '22 at 11:35
  • @dfrib: Why wouldn’t you use a (non-defining) explicit specialization declaration, which says what you mean and works? – Davis Herring Jun 18 '22 at 02:41
  • @DavisHerring Yes that would be the reasonable thing to do. I don't remember why I was interested in the explicit instantiation declaration approach when the "follows elsewhere" is this Q&A is an explicit specialization definition (and not an explicit instantiation definition). – dfrib Jun 20 '22 at 07:21

2 Answers2

1

Looks like this exact case is covered in the standards committee's "Closed Issues List", which you can read here, very hard to get more authoritative than that.

TL;DR:

Rationale (March, 2016):

As stated in the analysis, the intent is for the example to be ill-> formed, no diagnostic required.

Note that you can find quite a few SO questions that are pretty similar to this. I found this one for example, in which one answerer cites the working group discussion.

Jon Reeves
  • 2,426
  • 3
  • 14
-1

Therefore I wonder, is the following program ill-formed, NDR?

It is. This is main.cpp after all the pre-processing:

template <class> void foo(); // forward declaration of templated entity

int main() {
  foo<int>(); // Implicit instantiation: Ill Formed; No diagnosis required.
}

You might get a linker error like: undefined reference to 'void foo<int>()'.
You might not get an error (pre-compiled header, dynamic library...)

Why is diagnosing not required?
Phase 4: Preprocessing (the code above is formed during this phase)
Phase 7: Compilation (producing translation units)
Phase 8: Template instantiation occurs
Phase 9: The last one. This is when the function definition is found (or not) and linked to the executable

See: Translation Phases

viraltaco_
  • 814
  • 5
  • 14