0

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);
}
mbed_dev
  • 1,450
  • 16
  • 33
  • 1
    Basically, no. The reason is that the calling code is really generating the function body by filling in the type it makes the call with. So the template body needs to have been seen by the compiler, not just the signature. (Of course there would be ways around this, but that was the motiviation 20-odd years ago when the rules were designed). – BoBTFish Aug 17 '18 at 10:35

2 Answers2

0

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.

M310
  • 397
  • 2
  • 13
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.

badola
  • 820
  • 1
  • 13
  • 26