It's my understanding from post that argument dependent lookup is used when template dependent names are bound at the point of instantiation. I understand the first simple form below, however am unsure how exactly ADL and binding works on the second. I have a specific question regarding overriding sort().
Appreciate if anyone can guide me on how ADL and binding is occurring in the second code post. Also, if there is a way to redefine sort() to not bind to the std::sort and to bind to some other implementation.
template<typename T> T f(T a) {
// Can find ::ns::g(Q) only via ADL on T for
// an instantiation of f with T == ::ns::Q.
return g(a);
}
namespace ns {
class Q {};
Q g(Q e) { return e; }
} // namespace ns
int main() {
(void) f(::ns::Q{});
return 0;
}
Form that I need help with:
#include <iostream>
#include <vector>
template<typename T>
void print_sorted(std::vector<T>& v)
{
//typename std::vector<T>::iterator it;
sort(v.begin(),v.end()); // ADL looks at return type of begin()?
for (const auto& x : v)
std::cout << x << '\n';
}
int main(int argc, char *argv[])
{
std::vector<std::string> v = {"b", "a"};
print_sorted(v); // sort using std::sort, then print using std::cout
return 0;
}
#include <algorithm> // adl of sort() would allow std::sort to be defined here
Compilation:
clang++ -pedantic -Wall -std=c++11 test187.cc && ./a.out
a
b
I tried the OP's code on Godbolt. Just as OP claimed, it compiles under Clang (and, it seems, on GCC as well). If #include <algorithm> is commented out, both compilers claim that the name sort is unknown to them.
I believe that the reason for this behaviour is that these compilers defer the instantiation of the print_sorted function until the end of the translation unit. The license to do so is given by C++17 [temp.point]/8:
A specialization for a function template, a member function template, or of a member function or static
data member of a class template may have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any such specialization that has a point
of instantiation within the translation unit, the end of the translation unit is also considered a point of
instantiation. A specialization for a class template has at most one point of instantiation within a translation
unit. A specialization for any template may have points of instantiation in multiple translation units.
If two different points of instantiation give a template specialization different meanings according to the
one-definition rule (6.2), the program is ill-formed, no diagnostic required.
In other words, regardless of where the function template specialization is instantiated, it is also considered to be instantiated at the end of the translation unit, and all such instantiations must have the same meaning, otherwise the program is ill-formed NDR.
Thus, the compiler writers may defer function template instantiations, as much as possible, until the end of the translation unit, possibly for efficiency reasons, without being concerned that this would change the meaning of the program. If it does change the meaning of the program, it means that the programmer messed up and the compiler is not required to catch this mistake. (See also CWG 993)
The wording of [temp.point]/8 is unclear as to whether it applies to the OP's program (since here, at one point of instantiation, the specialization is actually ill-formed due to using an undeclared name, as opposed to simply having a different meaning than it does at another point of instantiation). I think this is just a defect in the wording, and GCC and Clang are following the "spirit" of the rule.
Related
I would like to write a C++ function that will check that its template parameter class is incomplete, so only class declaration is available but not full definition with all class members.
My function incomplete() looks as follows together with some demo program:
#include <type_traits>
#include <iostream>
template <typename T, typename V = void> constexpr bool is_incomplete = true;
template <typename T> constexpr bool is_incomplete<T, std::enable_if_t<sizeof(T)>> = false;
template <typename T> constexpr bool incomplete() { return is_incomplete<T>; }
struct A;
void print() { std::cout << incomplete<A>(); }
struct A {}; //this line affects GCC
int main()
{
print();
}
It works well in Clang printing 1, but in GCC the program prints 0 despite the fact that A class is incomplete in function print.
https://gcc.godbolt.org/z/qWW3hqbEv
Is GCC wrong here or there is a fault in my program?
Which compiler is correct is currently undecided. It's CWG Issue 1845.
The current wording of 13.8.4.1 [temp.point] does not define the point of instantiation of a variable template specialization. Presumably replacing the references to “static data member of a class template” with “variable template” in paragraphs 1 and 8 would be sufficient.
Given that issue is still in drafting stage (and no normative wording exists yet it the latest available draft), it remains unresolved. It isn't clear if a variable template can have multiple points of instantiation or not (though the direction the issue reporter suggests is clear).
For entities with multiple points of instantiation, the end of the translation unit is one as well. Also, if two points disagree on the definition of template, it's an ODR violation, plain and simple. GCC seems to provide two points, so you see the result of that. And I tend to agree with GCC here. A variable template is in many ways a shorthand for a static data member of a class template, and static data members do have multiple points of instantiation.
Either way, this is playing with the risk of nasal demons. Checking a type for complete-ness is not really possible reliably if that state can change in a TU (and possibly even if it can change in the entire program).
It looks like the finding whether a class is incomplete will be a violation of one definition rule (ODR) if at some point it becomes complete, so there should be no valid solution to the question.
Some more quotes from https://eel.is/c++draft/temp.point that I was suggested:
1 For a function template specialization ... the point of instantiation ... immediately follows the namespace scope declaration or definition that refers to the specialization.
7 A specialization for a function template ... may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above,
for any such specialization that has a point of instantiation within the ... the translation-unit ..., the point after the ... [end of] the translation-unit is also considered a point of instantiation,
If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.
After I read the answer for this question, I am still asking question. The answer talks about location of point of instantiation as defined in [temp.point] but it is not evaluated if the instantiations are required.
[temp.inst] specifies when a function template specialization instantiation is required, the general rule is:
An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class,[...], unless such instantiation is required.
Moreover in some paragraph of this section of the standard, instantiation of declaration and instantiation of definition are considered separately.
Let's consider this code:
static void Yeap0(int);
template <class T>
void Yeap(T a){
Yop(a);
}
template <class T>
auto Yeap2(T a){
Yop(a);
return 0;
}
namespace x{
struct y{};
}
int main() {
Yeap0(0);//ok no definition required here
x::y ax{};
Yeap(ax); //the declaration is sufficient,
Yeap2(ax); //need to deduce auto => definition required
//compilation error
return 0;
}
namespace x{
void Yop(y){}
}
static void Yeap0(int){}
Gcc, Clang and MSVC produce only an error for Yeap2(ax), complaining that Yop is not defined at the point of instantiation of Yeap2.
But this error is not generated for Yeap(ax). From basic consideration this seems logical, only the declaration is needed, as for the none template function Yeap0.
But the lecture of [temp.inst]/4 let me perplex. It could be understood that the instantiation of Yeap is also required. But it seems that compilers have taken a more clever path.
Is the compilers behavior an extension?
Note: I will not accept the "no diagnostic required" answer. This would be an insult to intelligence: Could one believe that 3 compilers have taken special care to shut down diagnostics for case like Yeap(ax) but not for Yeap2(ax)?
The compiler complaining really comes from the fact that the function returns auto.
In the auto case you really hit
unless such instantiation is required.
which must come from the requirement dcl.spec.auto.
To verify that assessment you can replace in your code Yeap2 by:
template <class T>
auto Yeap2(T a){
Yeap(a);
return 0;
}
and there is no compilation error.
When compiling C++, gcc and clang seems to postpone the type-checking of template instantiations until after all declarations of the program have been processed. Is this guaranteed in the language?
To elaborate, I can keep a type incomplete at the point where a template is defined or a template instantiation is needed, as long as I complete the type somewhere later in the program:
class A;
class B;
extern A* pa;
// 1. template definition
template<typename T>
T* f() { return static_cast<T*>(pa); }
// 2. template instantiation
B* test() { return f<B>(); }
// 3. completing types
class A { };
class B : public A { };
Note that the definitions of A and B are required to type check the template instantiation (to make the static_cast valid). If you leave out step 3, step 2 will no longer compile.
In the organisation of my headers, can I rely that this order will be accepted by any standard C++ compiler?
The rule is called "two-phase name lookup".
The names, which are not dependant on the template parameters, are looked up and checked at definition, and the dependent names are checked at the point of instantiation.
For your example, there is one important detail: the end of translation unit is also considered a point of instantiation for function templates:
C++14 N4140 14.6.4.1 [temp.point] P8:
A specialization for a function template, a member function template, or of a member function or static
data member of a class template may have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any such specialization that has a point
of instantiation within the translation unit, the end of the translation unit is also considered a point of
instantiation.
Thus, although the type is incomplete at point "2", where explicit instantiation happens, it is complete at the end of file, which makes the template instantiation legitimate.
Note: Microsoft compiler does not implement this rule in full, violating the standard. In Microsoft compiler, all the lookup happens at the point of instantiation (thus the example should also work, but I don't have access to MSVC to check). Other major compilers do implement this rule correctly.
I've recently run into a situation while specializing templates that has made me uneasy:
foo.h:
template <class T>
void foo() {
std::cout << "This is the generic foo" << std::endl;
}
foo.cc:
#include "foo.h"
template <>
void foo<int>() {
std::cout << "This is foo<int>" << std::endl;
}
main.cc:
#include "foo.h"
int main() {
foo<int>();
}
So. I compile as follows:
g++ -c main.cc
g++ -c foo.cc
g++ -o main main.o foo.o
The output is "This is foo<int>". I like this output. But I'm worried that what I'm observing might be unique to gcc (I don't have access to other compilers so I can't check).
Here's what I think gcc is doing: When main.cc is compiled, I would expect it to emit the generic code for the foo call because it is not aware of the specialization in foo.cc. But by linking with foo.o, it uses the specialization instead because it has the same signature.
But is this bad to count on? I'm worried that other compilers (or maybe even different versions of gcc?) might mangle their signatures when they emit template code, in a way that linking with foo.o will not replace the generic action like I want it to. Is this a valid worry? I've read a lot of things that make me feel uneasy, but nothing that makes me feel confident about what is happening in my current situation.
I'm worried that what I'm observing might be unique to gcc (I don't have access to other compilers so I can't check).
You have good reasons to be worried: Your program is ill-formed, and the compiler is not even required to tell you!
Paragraph 14.7.3/6 of the C++11 Standard specifies:
If a template, a member template or a member of a class template is explicitly specialized then that specialization
shall be declared before the first 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
Your specialization must be visible from the point of instantiation in order for the program to have consistent behavior. In your case, it isn't: you are relegating it in a file which is not included by other translation units.
Paragraph 14.7.3/7 Standard is quite explicit about what happens when you fail to do this:
The placement of explicit specialization declarations for function templates, class templates, member functions
of class templates, [...], can affect whether a program is
well-formed according to the relative positioning of the explicit specialization declarations and their points of
instantiation in the translation unit as specified above and below. When writing a specialization, be careful
about its location; or to make it compile will be such a trial as to kindle its self-immolation.
I guess the last sentence makes it clear.
Here, what you should do is to declare your intention to introduce an explicit specialization of your function template before any implicit instantiation of the primary template would occur. To do so, do the following:
foo.h
template <class T>
void foo() {
std::cout << "This is the generic foo" << std::endl;
}
template <> void foo<int>(); // Introduce a declaration of your
// explicit specialization right
// after you defined the primary
// template!
By introducing a declaration right after the definition of the primary template, you make sure that wherever the primary template is visible, it will be known that a full specialization for it exists, saving you from self-immolation.
I have a template class that I declare in a header with one method and no definition of that method in the header. In a .cc file, I define specializations of that method without ever declaring them in the header. In a different .cc file, I call the method for different template parameters for which specializations exist. It looks like this:
foo.h:
template<typename T>
class Foo {
public:
static int bar();
};
foo.cc:
#include "foo.h"
template<>
int Foo<int>::bar() {
return 1;
}
template<>
int Foo<double>::bar() {
return 2;
}
main.cc:
#include <iostream>
#include "foo.h"
int main(int argc, char **argv) {
std::cout << Foo<int>::bar() << std::endl;
std::cout << Foo<double>::bar() << std::endl;
return 0;
}
This program compiles and links successfully with gcc 4.7.2 for all C++ standards (c++98, gnu++98, c++11, and gnu++11). The output is:
1
2
This makes sense to me. Because the main.cc translation unit does not see a definition of bar() or any specializations of it, it expects the calls to bar() to use explicit instantiations of an unspecialized definition of bar() in some other translation unit. But since name mangling is predictable, the specializations in foo.cc have the same symbol names as explicit instantiations of an unspecialized definition would, so main.cc is able to use those specializations without them ever being declared in that translation unit.
My question is this: is this an accident, or is this behaviour mandated by the C++ standard? In other words, is this code portable?
The most relevant prior question that I could find is Declaration of template class member specialization, but it doesn't cover this particular case.
(In case you're wondering why this matters to me, it's because I'm using code like this as a sort of compile-time look-up table and it's a lot shorter if I don't declare the specializations.)
The Standard (C++11) requires that explicit specializations be declared (but not necessarily defined) before they are first used:
(14.7.3/6) If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first 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. [...]
I believe that this will in practice only have an effect when your primary template definition includes the definition of the non-specialized version of one of the member functions. Because in that case, when the explicit specialization isn't declared, the existing primary definition may be used to compile the function inline into the code, and the specialization would end up not being used at link-time.
In other words, if there is no definition of the member function included in the primary template definition, your linker trick can probably be expected to work in practice, but it wouldn't conform with what the Standard says, and it can get you into real trouble as soon as you add an inline function definition to the primary template.