Out of line definition of template function vs in class - c++

I wondered if there was any advantages of declaring templates function out of line vs in the class.
I'm trying to get a clear understanding of the pros and cons of the two syntax.
Here's an example:
Out of line:
template<typename T>
struct MyType {
template<typename... Args>
void test(Args...) const;
};
template<typename T>
template<typename... Args>
void MyType<T>::test(Args... args) const {
// do things
}
Vs in class:
template<typename T>
struct MyType {
template<typename... Args>
void test(Args... args) const {
// do things
}
};
Are there language features that are easier to use with the first or second version? Does the first version would get in the way when using default template arguments or enable_if? I would like to see comparisons of how those two cases are playing with different language features like sfinae, and maybe potential future features (modules?).
Taking compiler specific behavior into account can be interesting too. I think MSVC needs inline in some places with the first code snippet, but I'm not sure.
EDIT: I know there is no difference on how these features works, that this is mostly a matter of taste. I want to see how both syntaxes plays with different techniques, and the advantage of one over the other. I see mostly answers that favors one over another, but I really want to get both sides. A more objective answer would be better.

There is no difference between the two versions regarding default template arguments, SFINAE or std::enable_if as overload resolution and substitution of template arguments work the same way for both of them. I also don't see any reason why there should be a difference with modules, as they don't change the fact that the compiler needs to see the full definition of the member functions anyway.
Readability
One major advantage of the out-of-line version is readability. You can just declare and document the member functions and even move the definitions to a separate file that is included in the end. This makes it so that the reader of your class template doesn't have to skip over a potentially large number of implementation details and can just read the summary.
For your particular example you could have the definitions
template<typename T>
template<typename... Args>
void MyType<T>::test(Args... args) const {
// do things
}
in a file called MyType_impl.h and then have the file MyType.h contain just the declaration
template<typename T>
struct MyType {
template<typename... Args>
void test(Args...) const;
};
#include "MyType_impl.h"
If MyType.h contains enough documentation of the functions of MyType most of the time users of that class don't need to look into the definitions in MyType_impl.h.
Expressiveness
But it is not just increased readibility that differentiates out-of-line and in-class definitions. While every in-class definition can easily be moved to an out-of-line definition, the converse isn't true. I.e. out-of-line definitions are more expressive that in-class definitions. This happens when you have tightly coupled classes that rely on the functionality of each other so that a forward declaration doesn't suffice.
One such case is e.g. the command pattern if you want it to support chaining of commands and have it support user defined-functions and functors without them having to inherit from some base class. So such a Command is essentially an "improved" version of std::function.
This means that the Command class needs some form of type erasure which I'll omit here, but I can add it if someone really would like me to include it.
template <typename T, typename R> // T is the input type, R is the return type
class Command {
public:
template <typename U>
Command(U const&); // type erasing constructor, SFINAE omitted here
Command(Command<T, R> const&) // copy constructor that makes a deep copy of the unique_ptr
template <typename U>
Command<T, U> then(Command<R, U> next); // chaining two commands
R operator()(T const&); // function call operator to execute command
private:
class concept_t; // abstract type erasure class, omitted
template <typename U>
class model_t : public concept_t; // concrete type erasure class for type U, omitted
std::unique_ptr<concept_t> _impl;
};
So how would you implement .then? The easiest way is to have a helper class that stores the original Command and the Command to execute after that and just calls both of their call operators in sequence:
template <typename T, typename R, typename U>
class CommandThenHelper {
public:
CommandThenHelper(Command<T,R>, Command<R,U>);
U operator() (T const& val) {
return _snd(_fst(val));
}
private:
Command<T, R> _fst;
Command<R, U> _snd;
};
Note that Command cannot be an incomplete type at the point of this definition, as the compiler needs to know that Command<T,R> and Command<R, U> implement a call operator as well as their size, so a forward declaration is not sufficient here. Even if you were to store the member commands by pointer, for the definition of operator() you absolutely need the full declaration of Command.
With this helper we can implement Command<T,R>::then:
template <typename T, R>
template <typename U>
Command<T, U> Command<T,R>::then(Command<R, U> next) {
// this will implicitly invoke the type erasure constructor of Command<T, U>
return CommandNextHelper<T, R, U>(*this, next);
}
Again, note that this doesn't work if CommandNextHelper is only forward declared because the compiler needs to know the declaration of the constructor for CommandNextHelper. Since we already know that the class declaration of Command has to come before the declaration of CommandNextHelper, this means you simply cannot define the .then function in-class. The definition of it has to come after the declaration of CommandNextHelper.
I know that this is not a simple example, but I couldn't think of a simpler one because that issue mostly comes up when you absolutely have to define some operator as a class member. This applies mostly to operator() and operator[] in expession templates since these operators cannot be defined as non-members.
Conclusion
So to conclude: It is mostly a matter of taste which one you prefer, as there isn't much of a difference between the two. Only if you have circular dependencies among classes you can't use in-class defintion for all of the member functions. I personally prefer out-of-line definitions anyway, since the trick to outsource the function declarations can also help with documentation generating tools such as doxygen, which will then only create documentation for the actual class and not for additional helpers that are defined and declared in another file.
Edit
If I understand your edit to the original question correctly, you'd like to see how general SFINAE, std::enable_if and default template parameters looks like for both of the variants. The declarations look exactly the same, only for the definitions you have to drop default parameters if there are any.
Default template parameters
template <typename T = int>
class A {
template <typename U = void*>
void someFunction(U val) {
// do something
}
};
vs
template <typename T = int>
class A {
template <typename U = void*>
void someFunction(U val);
};
template <typename T>
template <typename U>
void A<T>::someFunction(U val) {
// do something
}
enable_if in default template parameter
template <typename T>
class A {
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
bool someFunction(U const& val) {
// do some stuff here
}
};
vs
template <typename T>
class A {
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
bool someFunction(U const& val);
};
template <typename T>
template <typename U, typename> // note the missing default here
bool A<T>::someFunction(U const& val) {
// do some stuff here
}
enable_if as non-type template parameter
template <typename T>
class A {
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
bool someFunction(U const& val) {
// do some stuff here
}
};
vs
template <typename T>
class A {
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
bool someFunction(U const& val);
};
template <typename T>
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, int>>
bool A<T>::someFunction(U const& val) {
// do some stuff here
}
Again, it is just missing the default parameter 0.
SFINAE in return type
template <typename T>
class A {
template <typename U>
decltype(foo(std::declval<U>())) someFunction(U val) {
// do something
}
template <typename U>
decltype(bar(std::declval<U>())) someFunction(U val) {
// do something else
}
};
vs
template <typename T>
class A {
template <typename U>
decltype(foo(std::declval<U>())) someFunction(U val);
template <typename U>
decltype(bar(std::declval<U>())) someFunction(U val);
};
template <typename T>
template <typename U>
decltype(foo(std::declval<U>())) A<T>::someFunction(U val) {
// do something
}
template <typename T>
template <typename U>
decltype(bar(std::declval<U>())) A<T>::someFunction(U val) {
// do something else
}
This time, since there are no default parameters, both declaration and definition actually look the same.

Are there language features that are easier to use with the first or second version?
Quite trivial a case, but it's worth to be mentioned: specializations.
As an example, you can do this with out-of-line definition:
template<typename T>
struct MyType {
template<typename... Args>
void test(Args...) const;
// Some other functions...
};
template<typename T>
template<typename... Args>
void MyType<T>::test(Args... args) const {
// do things
}
// Out-of-line definition for all the other functions...
template<>
template<typename... Args>
void MyType<int>::test(Args... args) const {
// do slightly different things in test
// and in test only for MyType<int>
}
If you want to do the same with in-class definitions only, you have to duplicate the code for all the other functions of MyType (supposing test is the only function you want to specialize, of course).
As an example:
template<>
struct MyType<int> {
template<typename... Args>
void test(Args...) const {
// Specialized function
}
// Copy-and-paste of all the other functions...
};
Of course, you can still mix in-class and out-of-line definitions to do that and you have the same amount of code of the full out-of-line version.
Anyway I assumed you are oriented towards full in-class and full out-of-line solutions, thus mixed ones are not viable.
Another thing that you can do with out-of-line class definitions and you cannot do with in-class definitions at all is function template specializations.
Of course, you can put the primary definition in-class, but all the specializations must be put out-of-line.
In this case, the answer to the above mentioned question is: there exist even features of the language that you cannot use with one of the version.
As an example, consider the following code:
struct S {
template<typename>
void f();
};
template<>
void S::f<int>() {}
int main() {
S s;
s.f<int>();
}
Suppose the designer of the class wants to provide an implementation for f only for a few specific types.
He simply can't do that with in-class definitions.
Finally, out-of-line definitions help to break circular dependencies.
This has been already mentioned in most of the other answers and it doesn't worth it to give another example.

Separating the declaration from the implementation allows you to do this:
// file bar.h
// headers required by declaration
#include "foo.h"
// template declaration
template<class T> void bar(foo);
// headers required by the definition
#include "baz.h"
// template definition
template<class T> void bar(foo) {
baz();
// ...
}
Now, what would make this useful? Well, the header baz.h may now include bar.h and depend on bar and other declarations, even though the implementation of bar depends on baz.h.
If the function template was defined inline, it would have to include baz.h before declaring bar, and if baz.h depends on bar, then you'd have a circular dependency.
Besides resolving circular dependencies, defining functions (whether template or not) out-of-line, leaves the declarations in a form that works effectively as a table of contents, which is easier for programmers to read than declarations sprinkled across a header full of definitions. This advantage diminishes when you use specialized programming tools that provide a structured overview of the header.

I tend to always merge them - but you can't do that if they are codependent. For regular code you usually put the code in a .cpp file, but for templates that whole concept doesn't really apply (and makes for repeated function prototypes). Example:
template <typename T>
struct A {
B<T>* b;
void f() { b->Check<T>(); }
};
template <typename T>
struct B {
A<T>* a;
void g() { a->f(); }
};
Of course this is a contrived example but replace the functions with something else. These two classes require each other to be defined before they can be used. If you use a forward declaration of the template class, you still cannot include the function implementation for one of them. That's a great reason to put them out of line, which 100% fixes this every time.
One alternative is to make one of these an inner class of the other. The inner class can reach out into the outer class beyond its own definition point for functions so the problem is kind of hidden, which is usable in most cases when you have these codependent classes.

Related

class template and member function template with requires

I have a template class called Speaker, with a template member function called speak. These both have a requires clause. How do I define the member function outside of the class in the same header file?
// speaker.h
#include <concepts>
namespace prj
{
template <typename T>
requires std::is_integral<T>
struct Speaker
{
template <typename U>
requires std::is_integral<U>
const void speak(const Speaker<U> &speaker);
};
// what do I put here?
const void Speaker<T>::speak(const Speaker<U> &speaker)
{
// code
}
}
The rules for defining template members of class templates are the same in principle as they were since the early days of C++.
You need the same template-head(s) grammar component(s), in the same order
template <typename T> requires std::is_integral_v<T>
template <typename U> requires std::is_integral_v<U>
const void Speaker<T>::speak(const Speaker<U> &speaker)
{
// code
}
The associated constraint expression and template <...> form the template-head together.
As an aside:
const qualified return types are redundant in the best case, or a pessimization in the worst case. I wouldn't recommend it (especially over void).
I'd also recommend using concepts (std::integral) if including the library header, not type traits (std::is_integral) that may or may not be included. The concepts allow for the abbreviated syntax, which is much more readable:
template<std::integral T>
template<std::integral U>

Why do we need 'template <class T>' before implementing all templated class methods

If we have a standard class:
class Foo {
public:
int fooVar = 10;
int getFooVar();
}
The implementation for getFooVar() would be:
int Foo::getFooVar() {
return fooVar;
}
But in a templated class:
template <class T>
class Bar {
public:
int barVar = 10;
int getBarVar();
}
The implementation for getBarVar() must be:
template <class T>
int Bar<T>::getBarVar(){
return barVar();
}
Why must we have the template <class T> line before the function implementation of getBarVar and Bar<T>:: (as opposed to just Bar::), considering the fact that the function doesn't use any templated variables?
You need it because Bar is not a class, it's a template. Bar<T> is the class.
Bar itself is a template, as the other answers said.
But let's now assume that you don't need it, after all, you specified this, and I added another template argument:
template<typename T1, typename T2>
class Bar
{
void something();
};
Why:
template<typename T1, typename T2>
void Bar<T1, T2>::something(){}
And not:
void Bar::something(){}
What would happen if you wanted to specialize your implementation for one type T1, but not the other one? You would need to add that information. And that's where this template declaration comes into play and why you also need it for the general implementation (IMHO).
template<typename T>
void Bar<T, int>::something(){}
When you instantiate the class, the compiler checks if implementations are there. But at the time you write the code, the final type (i.e. the instantiated type) is not known.
Hence the compiler instantiates the definitions for you, and if the compiler should instantiate something it needs to be templated.
Any answer to this question boils down to "because the standard says so". However, instead of reciting standardese, let's examine what else is forbidden (because the errors help us understand what the language expects). The "single template" case is exhausted pretty quickly, so let's consider the following:
template<class T>
class A
{
template<class X>
void foo(X);
};
Maybe we can use a single template argument for both?
template<class U>
void A<U>::foo(U u)
{
return;
}
error: out-of-line definition of 'foo' does not match any declaration in 'A<T>'
No, we cannot. Well, maybe like this?
template<class U>
void A<U>::foo<U>(U u)
{
return;
}
error: cannot specialize a member of an unspecialized template
No. And this?
template<class U, class V>
void A<U>::foo(V u)
{
return;
}
error: too many template parameters in template redeclaration
How about using a default to emulate the matching?
template<class U>
template<class V = U>
void A<U>::foo(V u)
{
return;
}
error: cannot add a default template argument to the definition of a member of a class template
Clearly, the compiler is worried about matching the declaration. That's because the compiler doesn't match template definitions to specific calls (as one might be used to from a functional language) but to the template declaration. (Code so far here).
So on a basic level, the answer is "because the template definition must match the template declaration". This still leaves open the question "why can we not just omit the class template parameters then?" (as far as I can tell no ambiguity for the template can exist so repeating the template parameters does not help) though...
Consider a function template declaration
tempalte <typename T>
void foo();
now a definition
void foo() { std::cout << "Hello World"; }
is either a specialization of the above template or an overload. You have to pick either of the two. For example
#include <iostream>
template <typename T>
void foo();
void foo() { std::cout << "overload\n"; }
template <typename T>
void foo() { std::cout << "specialization\n"; }
int main() {
foo();
foo<int>();
}
Prints:
overload
specialization
The short answer to your question is: Thats how the rules are, though if you could ommit the template <typename T> from a definition of the template, a different way would be required to define an overload.

Specializing single method in a big template class

In C++ if you want to partially specialize a single method in a template class you have to specialize the whole class (as stated for example in Template specialization of a single method from templated class with multiple template parameters)
This however becomes tiresome in bigger template classes with multiple template parameters, when each of them influences a single function. With N parameters you need to specialize the class 2^N times!
However, with the C++11 I think there might a more elegant solution, but I am not sure how to approach it. Perhaps somehow with enable_if? Any ideas?
In addition to the inheritance-based solution proposed by Torsten, you could use std::enable_if and default function template parameters to enable/disable certain specializations of the function.
For example:
template<typename T>
struct comparer
{
template<typename U = T ,
typename std::enable_if<std::is_floating_point<U>::value>::type* = nullptr>
bool operator()( U lhs , U rhs )
{
return /* floating-point precision aware comparison */;
}
template<typename U = T ,
typename std::enable_if<!std::is_floating_point<U>::value>::type* = nullptr>
bool operator()( U lhs , U rhs )
{
return lhs == rhs;
}
};
We take advantage of SFINAE to disable/enable the different "specializations" of the function depending on the template parameter. Because SFINAE can only depend on function parameters, not class parameters, we need an optional template parameter for the function, which takes the parameter of the class.
I prefer this solution over the inheritance based because:
It requires less typing. Less typing probably leads to less errors.
All specializations are written inside the class. This way to write the specializations holds all of the specializations inside the original class , and make the specializations look like function overloads, instead of tricky template based code.
But with compilers which have not implemented optional function template parameters (Like MSVC in VS2012) this solution does not work, and you should use the inheritance-based solution.
EDIT: You could ride over the non-implemented-default-function-template-parameters wrapping the template function with other function which delegates the work:
template<typename T>
struct foo
{
private:
template<typename U>
void f()
{
...
}
public:
void g()
{
f<T>();
}
};
Of course the compiler can easily inline g() throwing away the wrapping call, so there is no performance hit on this alternative.
One solution would be to forward from the function, you want to overload to some implementation that depends on the classes template arguments:
template < typename T >
struct foo {
void f();
};
template < typename T >
struct f_impl {
static void impl()
{
// default implementation
}
};
template <>
struct f_impl<int> {
static void impl()
{
// special int implementation
}
};
template < typename T >
void foo< T >::f()
{
f_impl< T >::impl();
}
Or just use private functions, call them with the template parameter and overload them.
template < typename T >
class foo {
public:
void f()
{
impl(T());
}
private:
template < typename G >
void impl( const G& );
void impl( int );
};
Or if it's really just one special situation with a very special type, just query for that type in the implementation.
With enable_if:
#include <iostream>
#include <type_traits>
template <typename T>
class A {
private:
template <typename U>
static typename std::enable_if<std::is_same<U, char>::value, char>::type
g() {
std::cout << "char\n";
return char();
}
template <typename U>
static typename std::enable_if<std::is_same<U, int>::value, int>::type
g() {
std::cout << "int\n";
return int();
}
public:
static T f() { return g<T>(); }
};
int main(void)
{
A<char>::f();
A<int>::f();
// error: no matching function for call to ‘A<double>::g()’
// A<double>::f();
return 0;
}
Tag dispatching is often the clean way to do this.
In your base method, use a traits class to determine what sub version of the method you want to call. This generates a type (called a tag) that describes the result of the decision.
Then perfect forward to that implememtation sub version passing an instance of the tag type. Overload resolution kicks in, and only the implememtation you want gets instantiated and called.
Overload resolution based on a parameter type is a much less insane way of handling the dispatch, as enable_if is fragile, complex at point of use, gets really complex if you have 3+ overloads, and there are strange corner cases that can surprise you with wonderful compilation errors.
Maybe i'm wrong but chosen best anwser provided by Manu343726 has an error and won't compile. Both operator overloads have the same signature. Consider best anwser in question std::enable_if : parameter vs template parameter
P.S. i would put a comment, but not enough reputation, sorry

Can non-templated nested classes of class templates be implemented in a C++ header?

Suppose a header file myheader.hxx defines a class template A in which a non-templated class B is defined (that does not depend on the template parameter of A):
template<class T>
class A {
class B {
// ...
};
};
Is it okay in this case to implement B in myheader.hxx, or do I need to write a separate myheader.cxx to avoid duplicate definitions at link time? Is this case handeled consistently by different compilers?
It's still either a template (or part of template, don't know the ultra-precise definitions) even if it's not the top-level template, so you need to should implement it in the header (technically, it can be in a source file if that's the only place it's used, but that probably defeats the purpose).
Note: if you're not going to implement its member functions inline with the class definition, you need syntax like:
template<typename T>
void A<T>::B::foo(...)
{
// ...
}
Also, because it's come up before, if B happened to have its own template parameter, it would be something like:
template<typename T>
template<typename T2>
void A<T>::B<T2>::foo(...)
{
// ...
}
Not:
template<typename T, typename T2>
void A<T>::B<T2>::foo(...)
{
// ...
}
Or if B didn't but B::foo did, it would be:
template<typename T>
template<typename T2>
// void A<T>::B::foo<T2>(...) // not this apparently
void A<T>::B::foo(...)
{
// ...
}
EDIT: apparently it's foo above instead of foo<T2> for a function, at least with GCC (so almost 100% sure that's standard behavior)...I'm sure some language lawyer will be able to explain why :)
Etc.

Syntax for Templated Member Functions

Consider the following code:
template <typename Datatype>
class MyClass
{
void doStuff();
template <typename AnotherDatatype>
void doTemplateStuff(AnotherDatatype Argument);
};
template <typename Datatype>
void MyClass<Datatype>::doStuff()
{
// ...
}
template <typename Datatype>
template <typename AnotherDatatype>
void MyClass<Datatype>::doTemplateStuff(AnotherDatatype Argument)
{
// ...
}
The implementation for the second member function, doTemplateStuff, will not compile if I condense it like this:
template <typename Datatype, typename AnotherDatatype>
void MyClass<Datatype>::doTemplateStuff(AnotherDatatype Argument)
{
// ...
}
Why is this? Shouldn't separating template information by commas have the same effect as putting each typename on its own line? Or is there some subtle difference I'm not aware of...?
(Also, if someone can think of a better title please let me know.)
This is an excellent question. I don't know the specific reason that the standards committee decided to design templates this way, but I think it's a callback to lambda calculus and type theory. Mathematically speaking, there is an isomorphism between any function that takes two arguments and returns a value and a function that takes in a single argument, then returns a function that takes in yet another argument and then returns a value. For example:
λx. λy. x + y
is isomorphic with (but not identical to)
λ(x, y). x + y
where (x, y) is a single object representing the pair of x and y.
With C++ member function templates, C++ chose to use the first of these systems. You have to specify all the arguments for the outermost function, then, separately, all of the arguments for the innermost function. Mathematically this is equivalent to specifying all of the arguments at the same time in one argument list, but C++ didn't choose to do this.
Now, a really good question is why they didn't do this. I'm not fully sure of the rationale, but if I had to guess it's because of weird interactions with template specialization. If I can think of something specific I'll update this post.
Putting comma's between the template declaration tells the compiler to expect two template parameters. In your case, because the object is a template object when you declare the function as you do you're violating your own declaration. It's looking for that second template in the MyClass object, referencing the actual class declaration and realizing that it's an error.
Hence,
template<typename T, typename V>
struct Foo{
void bar();
};
template<typename T, typename V>
void Foo<T,V>::bar(){...}
is what it's expecting to see.
template<typename T>
struct Foo{
void bar();
}
template<typename T, typename V>
void Foo<T>::bar(){...}
is an error. It's wondering where that other template parameter came from.
If you want to do this you'll need to write the function right there:
template<typename T>
struct Foo{
template<typename V>
void bar(const V& _anInputValue){
cout << _anInputValue;
}
void baz();
};
template<typename T>
void Foo<T>::baz(){
cout << "Another function.";
}