Declaration of methods with template arguments in implementation file - c++

Is it somehow possible to separate the definition and declaration of a class-method with template arguments (especially used when using constexpr functions) in distinct places? Because aren't "template arguments" like explicit specializations of template-functions?
Or is this situation tangled with the already well-discussed topics:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
Why can templates only be implemented in the header file?
E.g.:
Header file "someHeader.h"
#include <iostream>
#pragma once
class cc
{
public:
cc()=default;
~cc()=default;
template<uint32 f_val2Check_u32>
constexpr uint32 isPowerOf2();
private:
};
Then the *.cpp file:
// cpp-file
#include "someHeader.h"
template<uint32 val>
constexpr uint32 cc::isPowerOf2()
{
return ((val&(val-1))==0);
}

The problem is that templates are instantiated at compile time.
So it needs to see the definition of the function or class to understand what all class of operations would be applied on the type being passed.
Lets say in your function declaration :
template <typename T> void print_square(T t)
By seeing this what can you tell about :
"What all operations are going to be applied on the type T" ?
Honestly, nothing.
Now lets have a look at function definition :
template <typename T>
void print_square(T t)
{
std::cout << t * t;
}
Now when we see the function definition, we can tell that a binary operator * should be applicable on the type T.
This is the requirement on the type being passed to template.
In better words, the class of operations applicable of the type T being passed.
Hence, the compiler needs access to the function definition of a function template.
It can stop you from passing std::string as an argument to print_square(), since it doesn't meet the requirement.

The compiler must know what's the implementation of the function in all the translation units where it is used. The constexpr keyword tells the compiler to compute the result of the function for the given parameters at compile time and propagate that value. Without the implementation this cannot be achieved.
This would work on non-template non-constexpr functions because the value can be computed at run time, i.e. after linking.

Related

Template function specialization symbol matching across libraries

So far, I had a setup where a certain function template getF was declared like this in the headers
template <typename T> F* getF();
leaving the function body undefined. Then on a shared library, getFhas some specializations..
template<>
F* getF<int>()
{
static int r = 42;
static Finstance(r);
return &Finstance;
}
template<>
F* getF<float>()
{
static float r = 3.14159;
static Finstance(r);
return &Finstance;
}
The above has work so far nicely, as when on a client executable I invoke getF<float>(), the linker will replace with the appropriate references, and if the specialization doesn't exist in the library, then the compilation will fail with a linker error (which was the desired behavior)
However, Now there should be a small change in the behavior: when the result is not specialized for a given template parameter, the code should build, but return 0 at run-time.
So what I did is change the declaration of getF like this:
template <typename T> F* getF() { return 0; }
The problem is that, now the compiler will use this definition for all cases, regardless if there is an specialization in the library
Question: Is there some other way to provide some default behaviour for the function at runtime, without moving the
specializations to header files?
The best solution is to declare that the library's explicit specializations exist.
// All in the same header file:
template <typename T> F* getF() { return 0; }
template <> F* getF<int>();
template <> F* getF<float>();
This satisfies the rule from Standard 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.
Essentially you want the following: "enable special cases of F when T is int or float". It is exactly what constructs like boost::enable_if and std::enable_if are about.
There are subtle differences in enabling/disabling functions vs. classes (classes are easier). See good examples here: boost::enable_if not in function signature
You might need some MPL (Boost Meta-programming Library) to express the "or" part of your rule.

Is it safe to place definition of specialization of template member function (withOUT default body) in source file?

Here's what I mean:
// test.h
class cls
{
public:
template< typename T >
void f( T t );
};
-
// test.cpp
template<>
void cls::f( const char* )
{
}
-
// main.cpp
int main()
{
cls c;
double x = .0;
c.f( x ); // gives EXPECTED undefined reference (linker error)
const char* asd = "ads";
c.f( asd ); // works as expected, NO errors
return 0;
}
This is completely fine, right?
I started doubting this, because I just ran over the specialization of '...' after instantiation error, which was new to me. So, I "worked around" this error and everything seems to work fine now, but still..
Is this well-defined behavior?
edit: And the same for non-member template functions (forward declared non-member template functions).
Lightness Races in Orbit cited why it's not compliant parts from the Standard. There might be some others, in the vicinity.
I will try to explain in simpler terms what the Standard verbiage means, and hopefully I'll get it correctly, and finally explain the linker errors (or absence of error):
What is the point of instantiation ?
How does the compiler select a specialization ?
What is necessary at the point of instantiation ?
Why a linker error ?
1/ What is the point of instantiation ?
The point of instantiation of a template function is the point where it is called or referred to (&std::sort<Iterator>) with all the template parameters fleshed out (*).
template <typename T>
void foo(T) { std::cout << typeid(T).name() << "\n"; }
int main() { foo(1); } // point of instantiation of "foo<int>(int)"
It can be delayed though, and thus not match the exact call site, for templates called from other templates:
template <typename T>
void foo(T) { std::cout << typeid(T).name() << "\n"; }
template <typename T>
void bar(T t) { foo(t); } // not a point of instantiation, T is still "abstract"
int main() { foo(1); } // point of instantiation of "bar<int>(int)"
// and ALSO of "foo<int>(int)"
This delay is very important as it enables writing:
co-recursive templates (ie, templates that refer to each-others)
user-specializations
(*) Roughly speaking, there are exceptions such as non-template methods of a template class...
2/ How does the compiler select a specialization ?
At the point of instantiation, a compiler need to be able to:
decide which base template function to call
and possibly, which of its specializations to call
This old GotW shows off the woes of specializations... but in short:
template <typename T> void foo(T); // 1
template <typename T> void foo(T*); // 2
are overloads, and each spawns a distinct family of possible specializations of which they are the base.
template <> void foo<int>(int);
is a specialization of 1, and
template <> void foo<int*>(int*);
is a specialization of 2.
In order to resolve the function call, the compiler will first pick the best overload, while ignoring template specializations, and then, if it picked a template function, check if it has any specialization that could better apply.
3/ What is necessary at the point of instantiation ?
So, from the way a compiler resolve the call, we understand why the Standard specifies that any specialization should be declared before its first point of instantiation. Otherwise, it simply would not be considered.
Thus, at the point of instantiation, one needs to have already seen:
a declaration of the base template function to be used
a declaration of the specialization to be selected, if any
But what of the definition ?
It is not needed. The compiler assumes it will either be provided later on in the TU or by another TU entirely.
Note: it does burden the compiler because it means it needs to remember all the implicit instantiations it encountered and for which it could not emit a function-body so that when it finally encounters the definition it can (at last) emit all the necessary code fo all the specializations it encountered. I wonder why this particular approach was selected, and also wonder why even in the absence of an extern declaration the TU may end with undefined function-bodies.
4/ Why a linker error ?
Since no definition is provided, gcc trusts you to provide it later and simply emits a call to an unresolved symbol. If you happen to link with another TU that provides this symbol, then everything will be fine, and otherwise you'll get a linker error.
Since gcc follows the Itanium ABI we can simply look up how it mangles the symbols. It turns out that the ABI makes no difference in mangling specializations and implicit instantiations thus
cls.f( asd );
calls _ZN3cls1fIPKcEEvT_ (which demangles as void cls::f<char const*>(char const*)) and the specialization:
template<>
void cls::f( const char* )
{
}
also produces _ZN3cls1fIPKcEEvT_.
Note: it is not clear to me whether an explicit specialization could have been given a different mangling.
No, I don't think it's okay:
[C++11: 14/6]: A function template, member function of a class template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required.
[C++11: 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. [..]
Frankly I can't explain why it works for you.
I think that your original code was incorrect and your "workaround" is not standard-compliant, too (despite the fact that your compiler and linker process it). Good quotes from the standard were cited in the answer of #Lightness Races in Orbit. See also the following example from the standard ([temp.expl.spec] 14.7.3/6):
class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v) {
sort(v); // use primary template
// sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialization
// after use of primary template
template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
I marked my answer as community wiki because in fact it is only a big comment.

A C++ template is just "grammar safe" and not type safe first?

C++ templates are checked at least twice. First, when a template is declared & defined, second when it is instantiated. After a template successfully instantiated it is in a type safe state. My question is that what is the name of the state where a template is in when a template is successfully declared & defined?
If I compare macro with templates, is it true that after a successful macro "instantiation" the code is type safe?
#define BAR(x) return x;
^
// BAR is preprocessor-grammar-safe here?
struct Bar
{
static void bar() {}
};
^
// Bar is type safe at this point?
template<typename T>
void foo()
{
T::bar();
}
^
// foo is C++-grammar safe at this point?
int main()
{
foo<Bar>();
^
// foo is type safe at this point?
foo<int>();
^
// foo is ill-formed here?
BAR(0);
^
// BAR is type safe at this point?
return 0;
}
Think of a C++ template as a macro on steroids and having syntactical knowledge.
ex.
template<typename T>
void func(T t) {
t.foo();
...
Nothing declares the fact that T must have a foo() function;
This distinguishes C++ templates from things like Scala type parameters.
I believe newer C++ versions have added some support for this. You basically let the compile "try" using the t.foo() and if there's no such function it fails to compile.
A template is a template.
A type is a type.
Types may be obtained by specializing templates ("instantiating" in colloquial speech).
Templates and types have names. Types that are unions and classes must be declared, and defined in order to be complete. Templates must be declared, and defined in order to specialized.
That's all I can think of, and that should be enough vocabulary to talk about most aspects of the type system of C++ on a "first draft" kind of level.
You just miss a little point: Macro processing is text processing (done before compilation)
Assuming preprocessing has generated valid code:
A template can be successfully declared. Instantiation (definition) might fail, however.
Essentially BAR(0); is not type safe (exaggerating a bit here) !

Template class member specialization without declaration in header

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.

Why should the member function declarations of a class template be all well-formed?

OK, suppose I want to check whether the template parameter has a nested type/typedef XYZ.
template <class T>
struct hasXZY
{
typedef char no;
typedef struct { char x[2]; } yes;
template <class U>
static yes f(typename U::XYZ*);
template <class /*U*/>
static no f(...);
enum {value = sizeof(f<T>(0))==sizeof(yes)};
};
Works fine, as expected.
Now consider this:
template <class T>
struct hasXZY
{
typedef char no;
typedef struct { char x[2]; } yes;
static yes f(typename T::XYZ*);
static no f(...);
enum {value = sizeof(f(0))==sizeof(yes)};
};
hasXYZ<int> now results in a compile-time error. OK, f is not a template function. But on the other hand when hasXYZis instantiated for int via hasXYZ<int>::value, the compiler could easily just exclude f(int::XYZ*) from candidate list. I just don't understand why a failure in the instantiation of a member functions declaration in a class template must make the whole class instantiation fail. Any ideas?
Edit: My question is: why should the member function declararions be all well-formed? Since the compiler instantiates the methods only upon their usage, why does it need correct declaration. Consider the above example2 as a possible use-case of this feature.
SFINAE is used only when creating a candidate set for a function overload resolution. In your first example, you are calling the overloaded f() function, and the first one is excluded thanks to SFINAE.
In your second example, when instantiate hasXZY, all its members must be well defined, and the substitution of the template parameter must not fail. It does for int::XYZ.
Members will not be excluded from the class because of a substitution failure.
I'm not a C++ language lawyer, but I'll have a go at this.
In your second example, the member functions must be well-defined because they are no longer template functions once hasXZY is instantiated for int. To convince yourself of this, do the substitution for T "by hand":
struct hasXYZ
{
typedef int T;
typedef char no;
typedef struct { char x[2]; } yes;
static yes f(T::XYZ*);
static no f(...);
enum {value = sizeof(f(0))==sizeof(yes)};
};
int main()
{
std::cout << hasXYZ::value << "\n";
}
and observe that this fails to compile, with the same compiler error as before (in GCC, at least):
foo.cc:9: error: ‘T’ is not a class or namespace
By contrast, the first example compiles and behaves as expected after manual instantiation; the f members are still templated on U.
Edit: My question is: why should the member function declararions be all well-formed? Since the compiler instantiates the methods only upon their usage, why does it need correct declaration. Consider the above example2 as a possible use-case of this feature.
When implicitly instantiating a class template specialization, the compiler has to inspect the complete declarator of that member because it needs to know basic information about the declaration. Such can contribute to the size of the class template specialization.
If inspecting the declaration part will find out it's declaring a data-member, the sizeof value of the class will possibly yield a different value. If you would have declared a function pointer instead, this would be the case
yes (*f)(typename T::XYZ*);
The C++ language is defined in such a way that the type of a declaration is known only once the whole declaration is parsed.
You can argue that you put static there, and thus in this case this is not needed to compute its size. But it is needed for name-lookup to know what a name hasXZY<T>::f refers to and that there was declared a name f at all. The compiler will not instantiate the definition of hasXYZ::f, but it will only instantiate the non-definition part of the declaration, to gets its type and adding its name to the class type for name lookup purposes. I believe supporting delayed-instantiation for declaration of names in particular cases where it would possibly work would complicate implementation of C++ compilers and the C++ spec even more, for no comparable benefit.
And finally, in your example where you attempt to call it, the compiler has to instantiate the declaration, because it needs to lookup the name f, and for this it needs to know whether that declaration is a function or something else. So I really even theoretically can't see a way your example could work without instantiating the declaration. Note that in any case, these will not instantiate a definition of the function.