0

I have defined some static functions in their own .h and .cpp files, so these may be called from elsewhere without need for instantiation:

functions.h

#pragma once
class functions {
public:
    static const int addition(const int&, const int&);
    static const int product(const int&, const int&);
};

functions.cpp

#include "functions.h"
const int functions::addition(const int& op1, const int& op2) {
    return op1 + op2;
}
const int functions::product(const int& op1, const int& op2) {
    return op1 * op2;
}

I have also created a section for program settings where I will define which of the functions to pick:

constants.h

#pragma once
const int modulus = 10;
extern const int(*operation)(const int&, const int&);

constants.cpp

#include "constants.h"
#include "functions.h"
const int(*operation)(const int&, const int&) = &functions::addition;

This code works as expected using the following sample:

main.cpp

#include <iostream>
#include "constants.h"
int main() {
    int a = 7, b = 4;
    std::cout << operation(a,b) % modulus << std::endl;
}

Problem is, now I would like to parametrize the functions addition and product using a non-type template, such as:

functions.h

#pragma once
class functions {
public:
    template<const int&> static const int addition(const int&, const int&);
};

functions.cpp

#include "functions.h"
template<const int& sub> const int functions::addition(const int& op1, const int& op2) {
    return op1 + op2 - sub;
}

The later code breaks, no matter how I try to adapt the other files. I have done everything I reasonably (and pointlessly) could imagine.

Any help on how to rewrite the code on constants.* will be very appreciated.

jvier
  • 21
  • 4
  • Side note: you don't need that first class. If you want a separate namespace for your functions, use a namespace. – molbdnilo Apr 12 '16 at 12:50
  • Thank you for your advice, but the class groups other functions which deal with the given functions. Since they didn't play any role in the issue, I decided to exclude them from the minimal example. – jvier Apr 12 '16 at 12:59
  • I don't see how that matters. A class that only has static members is more a Java/C#/Smalltalk thing. – molbdnilo Apr 12 '16 at 13:15
  • @molbdnilo, you are not correct. There is a big difference between class with all static members and a namespace. – SergeyA Apr 12 '16 at 13:23
  • I feel safer encapsulating within a class, as I guess it allows me to later define non-static members in the case I ever need object instantiation. Anyways, I will consider using namespaces, if applicable. – jvier Apr 12 '16 at 14:19
  • Thank you two, guys. I have learned quite a bit of advanced topics on C++ from your replies and comments. – jvier Apr 12 '16 at 15:05

2 Answers2

0

Templates are instantiated at compile time, and for that the definition must be known - you need to have the template definition in the header.

Even if you do that, you don't have an int as the parameter but a const int&.
That means that you need to instantiate it with an lvalue whose identity (i.e. location) can be determined at compile-time.
In turn, that means that the parameter must be a variable with external linkage - not a temporary or a local variable.

In other words:

extern int x;

void foo()
{
    addition<1>(2,3); // Not good; not an lvalue
    const int y = 1;
    addition<y>(2,3); // Not good; no linkage
    addition<x>(2,3); // Good
}

You probably want to use template<int sub> instead.

(Another side note: const references to primitive types are pointless. All they do is add overhead.)

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • Thank you very much! I guess it is my turn now to decide where to define the variable x. As for passing references to primitive types, it is not the case of my original code, for sure. Added: I'm considering redefining as an int, but I can recall that cause other errors. Cheers. – jvier Apr 12 '16 at 14:11
  • Using template still won't compile for the same reason, unresolved external symbol. – jvier Apr 12 '16 at 14:40
  • @jvier Did you put the definition in the header? (See [here](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file).) – molbdnilo Apr 12 '16 at 14:51
  • I'm sorry I didn't pay proper attention. I just moved the definition to the header, leaving no "translation unit" in the cpp file, and it worked. However, this looks to me as a naughty hack and not elegant at all, as the definition of the function should not go in a header in my book. Is there any other way to do things right? – jvier Apr 12 '16 at 14:59
  • @jvier The right way to implement templates is by including them in the translation unit where they're used. It may not be elegant, but neither is the rest of C++. – molbdnilo Apr 12 '16 at 15:03
0

Template definitions should either be visible to the compiler during instantiation, or explicitly instantiated. Since I highly doubt you can explicitly instantiate all your possible versions of integer template, you have put the defginitons into the header.

Than comes the problem of operations. Since it's a function pointer, it can only point to specific instance of your template - the one instantiated with specific integer template. Doubt it's usable at all.

I suggest to rethink your design.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Thank you! I'm constantly rethinking my design, but I though it would be a good idea to define operations as an instance of the function template. However, whatever I did threw external linkage issues when compiling. – jvier Apr 12 '16 at 14:13
  • I'm taking a deeper read of you comment and it's enlightening. So I guess, explicit instantiation must be one of those samples with recursive templates ("variadic", if my knowledge is OK). Thanks! – jvier Apr 12 '16 at 15:03