I would like to define the explicit specialization of a template function in a cpp file. Is that possible? To be more concrete, I have the following code, which compiles without errors:
//class.h
class myclass
{
public:
/* Constructor */
myclass();
/* Trigger fcn */
template<typename T> T Trigger(T rn);
private:
/* Specializations of the templated Trigger(...) function */
template<> int Trigger<int>(int rn)
{
int_do(rn);
}
template<> double Trigger<double>(double rn)
{
double_do(rn);
}
}
However, I having the definitions in the header file looks weird for me, so I would like to separate the definitions from the declarations, something like this:
//class.h
class myclass
{
public:
/* Constructor */
myclass();
/* Trigger fcn */
template<typename T> T Trigger(T rn);
private:
/* Specializations of the templated Trigger(...) function */
template<> int Trigger<int>(int rn);
template<> double Trigger<double>(double rn);
}
and:
//class.cpp
/* Specializations of the templated Trigger(...) function */
template<> int myclass::Trigger<int>(int rn)
{
int_do(rn);
}
template<> double myclass::Trigger<double>(double rn)
{
double_do(rn);
}
Is there any way to to this?
Your only error is declaring the specialisations inside the class. Declare them in the header, but outside the class:
class myclass
{
public:
myclass();
template<typename T> T Trigger(T rn);
};
/* Specializations of the templated Trigger(...) function */
template<> int myclass::Trigger<int>(int rn);
template<> double myclass::Trigger<double>(double rn);
and then you can define them in a source file, exactly as you have done.
Note that your first snippet doesn't compile (unless your compiler has a non-standard extension), since the specialisations can't be declared inside the class.
In addition to earlier answer regarding the positioning of the specialization:
You can define template functions in a .cpp file. This also means that they can only be instantiated within this translation object/file.
In your case, the partial specialization is declared in the .h, and other compilation units will expect their existence.
For example in
file tmp.h:
#include <iostream>
class T {
public:
template <typename T> void foo(const T& t)
{
std::cout << "generic foo" << std::endl;
}
};
// forward declaration of specialization
template<> void T::foo(const double& t);
file tmp.cpp:
#include "tmp.h"
template <> void T::foo(const double& t)
{
std::cout << "double foo" << std::endl;
}
file main.cpp:
#include "tmp.h"
int main(int argc, const char** argv)
{
T t;
t.foo(1.0);
t.foo(1);
return 0;
}
Now compiling both .cpp files will work fine:
g++ main.cpp tmp.cpp -o tmp
./tmp
double foo
generic foo
without the definition of the specialization:
g++ main.cpp -o tmp
/tmp/ccpCJr3B.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `void T::foo<double>(double const&)'
collect2: error: ld returned 1 exit status
Related
I am having problems passing lambda expressions as a parameter to a method of a template class.
If I compile the following code:
main.cpp:
#include "a.h"
int main(int argc, char** argv) {
A<int> o;
o.a([&](){ });
}
a.h:
template <typename T>
class A {
public:
template <typename Lambda>
void a(const Lambda& f) {
f();
}
};
It works fine.
However I do not want to have my implementation of class A in a.h, I want to put the code it in a separate cpp file.
So I now have
main.cpp:
Unchanged
a.h:
template <typename T>
class A {
public:
template <typename Lambda>
void a(const Lambda& f);
};
a.cpp:
#include "a.h"
template <typename T>
template <typename Lambda>
void A<T>::a(const Lambda& f) {
f();
}
template class A<int>;
I now get the following error:
In file included from test.cpp:1:0:
a.h:7:7: error: 'void A<T>::a(const Lambda&) [with Lambda = main(int, char**)::__lambda0; T = int]', declared using local type 'const main(int, char**)::__lambda0', is used but never defined [-fpermissive]
void a(const Lambda& f);
^
Why is that? How can I fix it?
I noticed if I put everything in the same cpp file, it works. The problem only occurs when I want to split it this way which is necessary to keep my code organized.
Thank you for your answer
This is very strange because even this works:
main.cpp
#include "a.h"
int main(int argc, char** argv) {
A<int> o;
o.a([&](){ });
}
template <typename T>
template <typename Lambda>
void A<T>::a(const Lambda& f) {
f();
}
template class A<int>;
a.h
template <typename T>
class A {
public:
template <typename Lambda>
void a(const Lambda& f);
};
This works.
For some reason,
It just won't work when I separate the main() and the method implementation in two distinct cpp files.
Why?
OK I think I have found an explanation.
When you split the code of a template class between a .h and a .cpp,
You need to make template instantiation explicit.
The problem is that lambda expressions have no specified type, therefore it is not possible to write a template explicit instance of that function for a lambda type.
What I want is impossible:
Is it possible to explicitly specialize template to match lambda?
Generally you can't really put the implementation of template functions/classes in a .cpp file. The reason is that when the .cpp file is compiled separately the compiler has no way to know what template parameters will be passed to it. So I think for your situation it's best to leave everything in a header file.
As others have said it is not possible to separate a template class from its implementation in header and cpp files. However, if the class itself is not a template but one of the member functions accepts a lambda then you can separate the implementation. To do this, do not use template to declare the lambda. Use std::function instead.
Header file a.h.
#include <functional>
namespace xx {
struct A {
void square(int num, std::function<void(int)>consumer);
};
}
CPP file a.cpp.
namespace xx {
void A::square(int num, std::function<void(int)>consumer) {
consumer(num * num);
}
}
Use this as follows.
#include "a.h"
#include <assert.h>
int main() {
xx::A a;
a.square(10, [](int result) {
assert(result == 100);
});
return 0;
}
I'm trying to make a function accept different arguments depending on the enum.
// cake.h
#pragma once
#include <utility>
enum class TYPE { CupCake, Jelly, BirthdayCake };
struct cake_tin { /* etc etc */ };
/** Fills in different ingredients for different types of cake */
template <TYPE, typename ...Args>
void fill_tin(cake_tin &tin, Args... args);
/** Bakes a cake */
template <TYPE type, typename ...Args>
void bake_cake(Args&&...args) {
cake_tin tin;
fill_tin<type>(tin, std::forward<Args>(args)...);
}
.cpp file contains the specialisations of the function
// cake.cpp
#include "cake.h"
// If I put this in cake.h, I get multiple definition error (since the template's fully specalised), but if I move this to the .cpp file, I get undefined reference when I compile
template <>
void fill_tin<TYPE::CupCake>(cake_tin &tin, int cherries) {
// ... etc etc
}
template <>
void fill_tin<TYPE::Jelly>(cake_tin &tin, bool wobble) {
// ... etc etc
}
For completeness
// main.cpp
#include "cake.h"
int main() {
bake_cake<TYPE::CupCake>(1);
}
Another file that includes cake.h
// other.cpp
#include "cake.h"
Compile with clang++ -Wall -Wextra -std=c++11 main.cpp other.cpp -o main
I've tried putting in declarations
template <> void fill_tin<TYPE::CupCake>(cake_tin &tin, int cherries);
template <> void fill_tin<TYPE::Jelly>(cake_tin &tin, bool wobble);
and still can't get that template instantiated. If I move the specialisations into the header then they'll cause redefinition when the header is included in multiple compilation units at the link stage.
My question is: How can I get this to work, or is there a better way of doing this?
Trying to mix template specialization with function overloading is always going to be horribly painful.
Either provide class template specializations:
template<TYPE> struct tin_filler; // undefined
template<> struct tin_filler<TYPE::CupCake> {
void operator()(cake_tin& tin, int cherries); };
template<> struct tin_filler<TYPE::Jelly> {
void operator()(cake_tin& tin, bool wobble); };
template <TYPE type, typename ...Args>
void bake_cake(Args&&...args) {
cake_tin tin;
tin_filler<type>()(tin, std::forward<Args>(args)...);
}
Or use integral_constant to reify the TYPE and use normal function overloading:
void fill_tin(std::integral_constant<TYPE, TYPE::CupCake>, cake_tin& tin, int cherries);
void fill_tin(std::integral_constant<TYPE, TYPE::Jelly>, cake_tin& tin, bool wobble);
template <TYPE type, typename ...Args>
void bake_cake(Args&&...args) {
cake_tin tin;
fill_tin(std::integral_constant<TYPE, type>(), tin, std::forward<Args>(args)...);
}
The former is more general, but the latter could well be clearer and simpler in this case.
This question is related to this one except that rather than dealing with typename template parameters, I am trying to use an enum non-type template parameter.
Is it possible to have a templated (class member function) with only specializations, no general (working) definition in the case of non-type template parameter?
I was able to get one version working, by declaration in the class body and providing specializations only, but any misuse calling with a non-defined template parameter doesn't produce an error until linking. What's worse is the missing symbol cryptically refers to the enum's integral value and not its name, so it would be confusing to other developers.
I was able to get the BOOST_STATIC_ASSERT technique from the referenced question to work for typename template parameter only.
This code demonstrates the idea. I don't want the CAT-version call to compile:
#include <iostream>
#include <boost/static_assert.hpp>
// CLASS HEADER FILE:
struct foo_class
{
enum AllowedTypes { DOG, CAT };
template <AllowedTypes type>
void add_one_third( double bar ) const
{
BOOST_STATIC_ASSERT_MSG(sizeof(type)==0, "enum type not supported.");
}
};
// CLASS SOURCE FILE
template<>
void foo_class::add_one_third<foo_class::DOG>( double bar ) const
{
std::cout << "DOG specialization: " << bar + 1./3. << std::endl;
}
// USER SOURCE FILE
int main()
{
std::cout << "Template Specialization!\n\n";
foo_class a;
a.add_one_third<foo_class::DOG>(3.0); // should succeed
// Compilation fails with or without the following line:
a.add_one_third<foo_class::CAT>(3.0); // should fail at compile-time
return 0;
}
Background:
I have a class member function that takes an enum "ArgType" and a name.
void declareKernelArgument( ArgType type, std::string name );
The definition has turned into an if..else..if..else list for the half-dozen or so allowed ArgType cases. I also have to have final case that throws an exception for an not-allowed ArgType. I'm thinking it would be cleaner to move ArgType to a template parameter, and provide a specialization for each allowed ArgType. Misuse would be caught at compile-time.
With partial specialization of a structure inside the class:
#include <iostream>
class foo_class
{
public:
enum AllowedTypes { T_DOUBLE, T_INT };
private:
template <AllowedTypes type, typename T>
struct AddOneThird;
template <typename T>
struct AddOneThird<T_DOUBLE, T> {
static void apply(T bar) {
std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
}
};
public:
template <AllowedTypes type>
void add_one_third( double bar ) const {
AddOneThird<type, double>::apply(bar);
}
};
int main() {
foo_class a;
a.add_one_third<foo_class::T_DOUBLE>(3.0);
// error: incomplete type ‘foo_class::AddOneThird<(foo_class::AllowedTypes)1u
// a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time
return 0;
}
With full specialization of a (friend) class:
#include <iostream>
class foo_class
{
public:
enum AllowedTypes { T_DOUBLE, T_INT };
// if needed
// template<AllowedTypes> friend struct AddOneThird;
public:
template <AllowedTypes type> void add_one_third( double bar ) const;
};
template <foo_class::AllowedTypes>
struct AddOneThird;
template <>
struct AddOneThird<foo_class::T_DOUBLE> {
static void apply(double bar) {
std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
}
};
template <foo_class::AllowedTypes type>
void foo_class::add_one_third( double bar) const {
AddOneThird<type>::apply(bar);
}
int main() {
foo_class a;
a.add_one_third<foo_class::T_DOUBLE>(3.0);
// error: incomplete type ‘AddOneThird<(foo_class::AllowedTypes)1u>’ used
// in nested name specifier
//a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time
return 0;
}
Utilizing C++11 or boost::enable_if:
#include <iostream>
#include <type_traits>
class foo_class
{
public:
enum AllowedTypes { T_DOUBLE, T_INT };
template <AllowedTypes type>
typename std::enable_if<type == T_DOUBLE>::type
add_one_third( double bar ) const {
std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
}
};
int main() {
foo_class a;
a.add_one_third<foo_class::T_DOUBLE>(3.0);
// error: no matching function for call to ‘foo_class::add_one_third(double)’
//a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time
return 0;
}
From Herb Sutter
It's a lot less intuitive to specialize function templates. For one thing, you can't partially specialize them -- pretty much just because the language says you can't.[2] For another thing, function template specializations don't overload. This means that any specializations you write will not affect which template gets used, which runs counter to what most people would intuitively expect. After all, if you had written a nontemplate function with the identical signature instead of a function template specialization, the nontemplate function would always be selected because it's always considered to be a better match than a template.
If you're writing a function template, prefer to write it as a single function template that should never be specialized or overloaded, and implement the function template entirely in terms of a class template. This is the proverbial level of indirection that steers you well clear of the limitations and dark corners of function templates. This way, programmers using your template will be able to partially specialize and explicitly specialize the class template to their heart's content without affecting the expected operation of the function template. This avoids both the limitation that function templates can't be partially specialized, and the sometimes surprising effect that function template specializations don't overload. Problem solved.
Your enum type sizeof is not 0, change that to 4 at least. Otherwise this will not work. A enum element size is not 0.
Without that everything runs
#include <iostream>
struct foo_class
{
enum AllowedTypes { DOG, CAT };
template <AllowedTypes type>
void add_one_third( double bar ) const
{
std::cout << "YES" << std::endl;
}
};
template<>
void foo_class::add_one_third<foo_class::DOG>( double bar ) const
{
std::cout << "DOG specialization: " << bar + 1./3. << std::endl;
}
int main()
{
std::cout << "Template Specialization!\n\n";
foo_class a;
a.add_one_third<foo_class::DOG>(3.0); // should succeed
// Compilation fails with or without the following line:
//a.add_one_third<foo_class::CAT>(3.0); // should fail at compile-time
return 0;
}
The main difference between the enum case and the referenced question using a typename parameter is that the default definition will be compiled for any use. So, a working solution is as simple as modifying the BOOST_STATIC_ASSERT condition to check allowed enum values.
#include <iostream>
#include <stdexcept>
#include <boost/static_assert.hpp>
// CLASS HEADER FILE:
struct foo_class
{
enum AllowedTypes { DOG, CAT, MOUSE };
template <AllowedTypes type>
void give_bath() const
{
// compile fails if ever attempting to use this function with CAT parameter.
BOOST_STATIC_ASSERT_MSG( (type==DOG) || (type==MOUSE) , "enum type not supported.");
throw std::runtime_error("Unexpected. Above list inconsistent with specializations.");
}
};
// CLASS SOURCE FILE
template<>
void foo_class::give_bath<foo_class::DOG>() const
{
std::cout << "DOG is bathed." << std::endl;
}
template<>
void foo_class::give_bath<foo_class::MOUSE>() const
{
std::cout << "MOUSE is bathed." << std::endl;
}
// USER SOURCE FILE
int main()
{
std::cout << "Template Specialization!\n\n";
foo_class a;
a.give_bath<foo_class::DOG>(); //success
a.give_bath<foo_class::MOUSE>(); // success
// Compilation fails with the following line:
//a.give_bath<foo_class::CAT>(); // fails at compile-time as intended.
return 0;
}
Of course, the whole design smells bad and could likely be handled more elegantly with AllowedTypes being a struct/class with inherited specializations. But this gets to the question at hand.
The problem I am struggling with is the declaration of specialized template function inside template class (I keep class declaration in header file and define member functions in associated .C file).
I have template class representing Points. The header file is presented below:
//...
template<typename T, int dim=3> // T - coords. type, int dim - no. of dimensions
class Point {
public:
// ...
// function below sets val at the given position in array m_c and returns reference
template<int position> Point& set(T val);
private:
T m_c[dim]; // coordinates
};
//...
definition of function set is placed in .C file:
template<typename T, int dim> template<int position> Point<T, dim>& Point<T, dim>::set(T val){
// ...
return *this;
}
As I understand this is the most general form of its definition.
In main function I create Point with float as T and try to set some values in the array:
int main(int argc, char** argv) {
Point<float> p1;
p1.set<0>(3).set<1>(3.6).set<2>(3);
//...
}
In order to make this possible with definition of the member functions of template outside header file I need to inform compiler about specialization in .C file:
template class Point<float>;
and I need as well to declare usage of set function, which I try to accomplish this way
(and this piece of code is the problem):
template<> template<int> Point<float>& Point<float>::set(float);
That unfortunately doesn't do the job and I get errors:
/tmp/ccR7haA5.o: In function `main':
.../pdim.C:32: undefined reference to `Point<float, 3>& Point<float, 3>::set<0>(float)'
.../pdim.C:32: undefined reference to `Point<float, 3>& Point<float, 3>::set<1>(float)'
.../pdim.C:32: undefined reference to `Point<float, 3>& Point<float, 3>::set<2>(float)'
I would really appreciate an explanation from someone who may know how to cope with this problem. Thanks.
In order to provide the definition of a function template specialization in a different TU, you need an explicit instantiation declaration:
[Point.hpp]
template<typename T, int dim=3>
struct Point
{
template<int position> Point& set(T val);
};
// `extern` makes this an explicit instantiation _declaration_
extern template Point<float,3>& Point<float,3>::set<0>(float);
extern template Point<float,3>& Point<float,3>::set<1>(float);
extern template Point<float,3>& Point<float,3>::set<2>(float);
[Point.cpp]
#include <iostream>
#include "Point.hpp"
template<typename T, int dim>
template<int position>
Point<T,dim>& Point<T,dim>::set(T val)
{
// note: non-standard macro
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
// no `extern`: this is an explicit instantiation _definition_
// which instantiates the function template, and therefore requires the definition
// to be available in this TU
template Point<float,3>& Point<float,3>::set<0>(float);
template Point<float,3>& Point<float,3>::set<1>(float);
template Point<float,3>& Point<float,3>::set<2>(float);
[main.cpp]
#include "Point.hpp"
int main()
{
// in this TU, there's no definition for the function template
// hence, it cannot be instantiated
// however, we can use the explicit instantiations
Point<float,3>().set<0>(0);
Point<float,3>().set<1>(0);
Point<float,3>().set<2>(0);
// does not compile (linker error):
//Point<int,3>().set<0>(0);
//Point<float,4>().set<0>(0);
//Point<float,3>().set<4>(0);
}
I'm seeing an error related to templates (compiler is Visual Studio 2012) that I don't understand. Here's the code, boiled down to the essentials:
// Templated class - generic
template <typename T>
class Test
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// Templated class - expicit specialization for T = int.
template <>
class Test<int>
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// The definition below compiles and works fine at runtime.
template<typename T> void Test<T>::Problem() {}
// The definition below gives error C2910.
template<> void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
For the WorksFine method, the function definition is inside the explicitly specialized class definition, and everything is fine. But for the Problem method, when I define the method outside the explicitly specialized class definition, I get error C2910
Why is this? Error C2910 indicates that the problem is that Test::Problem() is already defined. But it is not defined inside the class...there is no function definition only a declaration.
It seems pretty lame to be able to do something or not depending on where you choose to put the function definition, which I always though was more of a style/syntax decision, not a functionality/semantics decision. Am I missing something?
You don't need the template<>. Just write:
void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
The template<> syntax on a member specialization is required where explicitly instantiating a member on its own; it is omitted when defining a member of an already existing specialization.
template<typename T> struct X { static int i; };
template<> int X<int>::i = 0; // member instantiation, uses template<>
template<typename T> struct Y { static int i; };
template<> struct Y<int> { static int i; } // template specialization
int Y<int>::i = 0; // no template<>
You don't need template anymore in the explicit function definition: void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
In this case g++ gives a slightly better error message error: template-id 'Problem<>' for 'void Test<int>::Problem()' does not match any template declaration
Try this:
// The definition below gives error C2910.
void Test<int>::Problem()
{
printf("In Test::Problem(int instantiation)\n");
}
int main()
{
Test<int> hey;
hey.Problem();
return 0;
};