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.
Related
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.
I was learning some C++ idioms when I came across a sample code for SFINAE, I was perplexed with the code.
Note: is_ptr() has no definition.
I compiled the code myself, no compiler errors regarding lack of function definition, why?
sizeof() was used on one of the calls, it apparently executed on the returns of the functions, but then again, there was no definition. How was that possible?
template <typename T>
struct is_pointer
{
template <typename U>
static char is_ptr(U*);
template <typename X, typename Y>
static char is_ptr(X Y::*);
template <typename U>
static char is_ptr(U (*)());
static double is_ptr(...);
static T t;
enum {value = sizeof(is_ptr(t)) == sizeof(char)};
};
sizeof is what is called an un-evaluated context. Within it the expression needs to be only well formed, nothing will actually ever be executed. So a function that is only declared can be used inside without needing an actual definition.
This is because the definition is not required to determine the type information. In this case, the overload that is chosen by ADL is the type information in question. It's return type is also available from the declaration alone.
For example:
template <typename T>
struct foo
{
using bar = int;
};
// _Z3bazi
void baz(foo<int>::bar quux) {
}
template <typename T>
void baz(typename foo<T>::bar quux) {
}
// _Z3bazIiEvN3fooIT_E3barE
template void baz<int>(foo<int>::bar quux);
Why does the mangled form of baz<int> mention foo at all? How come it's not _Z3bazIiEvi?
This is apparently the reason that the C++17 std::default_order<T> proposal is dead in the water.
The issue comes from the <unresolved-name> construct in the ABI. Why would we ever want to use an unresolved name? It's all about declaration matching and overloads. C++14 §14.5.6.1/3 notes,
Two distinct function templates may have identical function return types and function parameter lists, even if overload resolution alone cannot distinguish them.
You can have another function in a different file,
template <typename T>
void baz(int quux) { std::abort(); }
Although this signature can't peacefully coexist in the same file — it cannot be named because of overload ambiguity — it can exist in a different file so it needs a distinct mangling.
(Even this level of coexistence is not guaranteed by the standard for all templates. It's a matter of QOI that the compiler uses the exact form of a function template declaration to perform declaration matching, so that copy-pasting a declaration into a definition will tend to provide an exact match and not a surprising conflict with another function template that resolves to the same signature. See §14.5.6.1/5-6.)
As for raining on default_order's parade, the problem is that template-ids implicitly pull default arguments from templates. So the user could unintentionally have a dependent typename in a signature just by mentioning std::set.
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.
Learning C++, came upon function templates. The chapter mentioned template specialization.
template <> void foo<int>(int);
void foo( int );
Why specialize when you can use the second? I thought templates were suppose to generalize. What's the point of specializing a function for a specific data type when you can just use a regular function?
Obviously, template specialization exists for a reason. When should it be used? I read Sutter's "Why not Specialize..." article but I need more of a layman's version since I'm just learning this stuff.
The main difference is that in the first case you are providing the compiler with an implementation for the particular type, while in the second you are providing an unrelated non-templated function.
If you always let the compiler infer the types, non-templated functions will be preferred by the compiler over a template, and the compiler will call the free function instead of the template, so providing a non-templated function that matches the arguments will have the same effect of specializations in most cases.
On the other hand, if at any place you provide the template argument (instead of letting the compiler infer), then it will just call the generic template and probably produce unexpected results:
template <typename T> void f(T) {
std::cout << "generic" << std::endl;
}
void f(int) {
std::cout << "f(int)" << std::endl;
}
int main() {
int x = 0;
double d = 0.0;
f(d); // generic
f(x); // f(int)
f<int>(x); // generic !! maybe not what you want
f<int>(d); // generic (same as above)
}
If you had provided an specialization for int of the template, the last two calls would call that specialization and not the generic template.
I personally can see no benefit from specializing a function template. Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).
Herb Sutter has written an article Why not specialize function templates? where he discourages specializing function templates in favour of either overloading them or writing them so that they just forward to a class template's static function and specializing the class template instead.
You can use specialization when you know for a specific class the generic method could be efficient.
template<typename T>
void MySwap(T& lhs, T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
Now for vectors my swap will work, but is not very effecient. But I also know that std::vector implements its own swap() method.
template<>
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
Please don;t compare to std::swap which is a lot more complex and better written. This is just an example to show that a generic version of MySwap() will work but is may not always be efficient. As a result I have shown how it can be made more efficient with a very specific template specialization.
We can also of course use overloading to achieve the same effect.
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
So the question if why use template specialization (if one can use overloading). Why indeed. A non template function will always be chosen over a template function. So template specialization rules are not even invoked (which makes life a lot simpler as those rules are bizarre if you are not a lawyer as well as a computer programmer). So let me thing a second. No can't think of a good reason.
I find it very important. You can use this as you would use a virtual method. There would be no point in virtual methods unless some of them were specialized. I have used it a lot to differentiate between simple types (int,short,float) and objects, object pointers and object references.
An example would be serialize/unserialize methods that would handle objects by calling the objects serialize/unserialize method, while simple types should be written directly to a stream.
One case for template specialization which is not possible with overloading is for template meta-programming. The following is real code from a library that provides some of it services at compile time.
namespace internal{namespace os{
template <class Os> std::ostream& get();
struct stdout{};
struct stderr{};
template <> inline std::ostream& get<stdout>() { return std::cout; }
template <> inline std::ostream& get<stderr>() { return std::cerr; }
}}
// define a specialization for os::get()
#define DEFINE_FILE(ofs_name,filename)\
namespace internal{namespace os{ \
struct ofs_name{ \
std::ofstream ofs; \
ofs_name(){ ofs.open(filename);} \
~ofs_name(){ ofs.close(); delete this; } \
}; \
template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \
}} \
using internal::os::ofs_name;
Multiple overloads on the same name do similar things. Specializations do the exact same thing, but on different types. Overloads have the same name, but may be defined in different scopes. A template is declared in only one scope, and the location of a specialization declaration is insignificant (although it must be at the scope of the enclosing namespace).
For example, if you extend std::swap to support your type, you must do so by specialization, because the function is named std::swap, not simply swap, and the functions in <algorithm> would be quite right to specifically call it as ::std::swap( a, b );. Likewise for any name that might be aliased across namespaces: calling a function may get "harder" once you qualify the name.
The scoping issue is confused further by argument-dependent lookup. Often an overload may be found because it is defined in proximity to the type of one of its arguments. (For example, as a static member function.) This is completely different from how the template specialization would be found, which is by simply looking up the template name, and then looking up the explicit specialization once the template has been chosen as the target of the call.
The rules of ADL are the most confusing part of the standard, so I prefer explicit specialization on the priciple of avoiding reliance on it.