I have a template class, which has two static member variables, one int and another an std::array<volatile uint_fast32_t, 8>. When I instantiate the template with two different classes (which are templates themselves) as template parameters, for one of the instantiations everything works perfectly, i.e. there is exactly one copy of both variables. However, for the other, the array appears in duplicate in the symbol table, and indeed my code has a bug that when I set a value in the array in one compilation unit, the change does not appear in another.
This is for an embedded system, which is the reason for this weird idiom of using static templates for a kind of compile-time polymorphism.
In code: Header declaring the class itself
//dacmux.h
namespace HAL {
template<typename dac_write_sequence_t,
unsigned int chans,
typename sample_t = uint_fast32_t>
struct dacmux {
private:
typedef std::array<volatile sample_t, chans> chans_t;
static chans_t channels;
static unsigned int nextchan;
...
};
//The static variables defined here,
//count on the compiler/linker to make sure
//there is exactly one definition
template<typename dac_write_sequence_t,
unsigned int chans,
typename sample_t>
typename dacmux<dac_write_sequence_t, chans, sample_t>::chans_t dacmux<dac_write_sequence_t, chans, sample_t>::channels{0};
template<typename dac_write_sequence_t, unsigned int chans, typename sample_t>
unsigned int dacmux<dac_write_sequence_t, chans, sample_t>::nextchan = 0;
template<typename dac_t, typename addr_t, typename en_t>
struct muxed_setter {
...
};
template<typename dac_t>
struct dac_setter {
...
};
}//namespace HAL
A header which distributes definitions of the hardware:
//Hardware_types.h
...
//Multiplexer for the internal DAC
typedef HAL::dacmux<HAL::muxed_setter<dac1, mux1_addr, mux1_en>, 8> mux1;
//Sequencer for writing the external DAC values
typedef HAL::dacmux<HAL::dac_setter<extdac1>, 8> extdac_sequencer;
...
The header Hardware_types.h is included in two source files, main.cpp, DebugConsole.cpp, both of which use both mux1 and extdac_sequencer.
As for as I understand, based on answers such as this one and many others, the compiler should take care that each of the static member variables is instantiated exactly once for each instantiation of the template?
However, when I set the values of extdac_sequencer::channels in DebugConsole.cpp, the changes are not reflected in an interrupt handler declared in main.cpp. The same works perfectly for mux1::channels. Indeed, an excerpt from the symbol table, extracted from the .elf by objdump -t:
20000280 l O .bss 00000004 _ZN3HAL6dacmuxINS_10dac_setterINS_6ti_dacINS_3SPIINS_5SPI_2EEEN5GPIOs5pin_tINS6_1BELj12EEENS_12_GLOBAL__N_110xx68_frameENSA_12command_xx68ENSA_12channel_xx68EEEEELj8EjE8nextchanE
...
20000254 l O .bss 00000020 _ZN3HAL6dacmuxINS_10dac_setterINS_6ti_dacINS_3SPIINS_5SPI_2EEEN5GPIOs5pin_tINS6_1BELj12EEENS_12_GLOBAL__N_110xx68_frameENSA_12command_xx68ENSA_12channel_xx68EEEEELj8EjE8channelsE
...
20000288 l O .bss 00000020 _ZN3HAL6dacmuxINS_10dac_setterINS_6ti_dacINS_3SPIINS_5SPI_2EEEN5GPIOs5pin_tINS6_1BELj12EEENS_12_GLOBAL__N_110xx68_frameENSA_12command_xx68ENSA_12channel_xx68EEEEELj8EjE8channelsE
...
20000234 w O .bss 00000020 _ZN3HAL6dacmuxINS_12muxed_setterIN4DACs11DAC_channelILj1EN5GPIOs5pin_tINS4_1AELj4EEEEENS4_12bit_stripe_tINS4_1CELj6ELj3EEENS5_ISA_Lj9EEEEELj8EjE8channelsE
...
2000027c w O .bss 00000004 _ZN3HAL6dacmuxINS_12muxed_setterIN4DACs11DAC_channelILj1EN5GPIOs5pin_tINS4_1AELj4EEEEENS4_12bit_stripe_tINS4_1CELj6ELj3EEENS5_ISA_Lj9EEEEELj8EjE8nextchanE
So the nextchan variable appears once per instantiation, as it should, and for mux1 so does channels. However, for extdac_sequencer, the channels variable is repeated, which I believe explains the bug.
Am I doing something wrong, or is this a compiler or linker bug?
Compiler: GCC arm-none-eabi 5.2.1 20151202
Linker: arm-none-eabi-ld 2.25.90.20151217
Linker options: -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"Synth1Firmware.map" -Xlinker --cref --specs=nano.specs
Update:
I've narrowed down the conditions for this to happen:
If the first template parameter of dacmux is not itself a template, everything works, i.e. no duplicate symbol:
struct extdac1_setter {
template<typename sample_t>
inline static void update(sample_t val, unsigned int addr) {
extdac1::write_and_update(val, addr);
}
};
//Multiplexer for external DAC, works
typedef HAL::dacmux<extdac1_setter, 8> extdac_sequencer;
However, if the template parameter is templated itself, I get the duplicate symbol problem:
template<typename dac_t>
struct dac_setter {
template<typename sample_t>
inline static void update(sample_t val, unsigned int addr) {
dac_t::write_and_update(val, addr);
}
};
//Multiplexer for external DAC, this produces a duplicate symbol
typedef HAL::dacmux<dac_setter<extdac1>, 8> extdac_sequencer;
Here, extdac1 is itself, again, a template:
typedef HAL::DAC8568<dacspi, typename dacspi::nss> extdac1;
...and dacspi is a template, and so on. Also, in the case which does work, with the other instantation, while dac_write_sequence_t is a template, it isn't anymore a template of templates. So I'm starting to think that this is a problem with template recursion depth, i.e. ld isn't looking deep enough.
A further interesting observation: on exactly the same condition as having the duplicate symbol, the Eclipse syntax highlighter says "invalid template parameters" on the line declaring extdac_sequencer, although the actual compilation step goes through.
Turns out this was my sillyness: I was using an unnamed namespace in a header that defines the template HAL::DAC8568, which is defined as
template<typename spi_t, typename nss_t> using DAC8568 = ti_dac<spi_t, nss_t,
xx68_frame,
command_xx68,
channel_xx68>;
Here xx68_frame, command_xx68, and channel_xx68 are all defined in the unnamed namespace (which is of course the wrong thing to do in a header). This of course means that when instantiated from a different compilation unit, I get a different type for each of them and therefore a different type for DAC8568 and so on, so it's perfectly natural to get another instance of the static variable.
Changing the unnamed namespace to namespace detail fixed the problem immediately.
I am still somewhat baffled by the fact that the mangled names in the linker output seem identical. How can that be?
Anyway, we learn from this the following (some of which we knew already):
I'm an instantiation of the simpleton -pattern
unnamed namespaces in headers are truly evil
bugs stemming from the above can be quite subtle
Related
I have the following code:
// template_header.hpp
#ifndef TEMPLATE_HEADER_HPP
#define TEMPLATE_HEADER_HPP
namespace template_header
{
template <int dim1>
/*static*/ constexpr int dim2 = 0;
template <>
/*static*/ constexpr int dim2<2> = 3;
template <>
/*static*/ constexpr int dim2<3> = 5;
}
#endif
// lib1.cpp
#include <array>
#include "template_header.hpp"
template <int dim1>
class lib1_class
{
public:
std::array< double, template_header::dim2<dim1> > ar1 = {0};
};
// lib2.cpp
#include <array>
#include "template_header.hpp"
template <int dim1>
class lib1_class
{
public:
std::array< double, template_header::dim2<dim1> > ar1 = {0};
};
If I compile any of the .cpp files with static uncommented, GCC gives me an "explicit template specialization cannot have a a storage class" error.
If static is commented, I can compile both .cpp files and then link them together as a shared library with g++ lib1.o lib2.o -shared -o shared_lib.so.
However, if I compile with static commented out with clang, I get no problems during compilation, but I get a "multiple definition of template_header::dim2<2>'" error during linking. If I uncomment static`, then everything compiles and links fine.
I'm pretty confused about this, firstly given that this answer indicates that, since my constexpr's happen in a namespace scope, they ought to automatically be static and therefore should pose no problem for the linker even if static is commented out.
Additionally, I don't understand why adding static beforehand would change how GCC compiles the .cpp files, given that it should be implicitly static.
Any explanation of the errors + possible fixes are appreciated.
Edit: I am using C++14.
So, without inline variables, I was able to get something achieving your goals working. The basic idea is to have a "backend" struct to hold static members and then fully specialize that struct to your options. This method has the added benefit of causing a compiler error if you attempt to access a member of the backend using a template parameter that has not been defined yet.
The header file would look like
#ifndef TEMPLATED_HEADER_HPP
#define TEMPLATED_HEADER_HPP
namespace template_header {
/**
* the "primary" template of the backend struct
* notice I leave the variable we want undefined!
* if you prefer to have a default for all other values of dim1
* you would put that here
*/
template<int dim1>
struct backend {};
template<>
struct backend<2> {
static constexpr int dim2 = 3;
};
template<>
struct backend<3> {
static constexpr int dim2 = 5;
};
/**
* Helper constexpr
* this is optional, but makes code outside this file more readable
* also, I named it in a way for your source files to be unchanged.
*/
template <int dim1>
constexpr dim2 = backend<dim1>::dim2;
}
#endif
I have a working version of this idea on Compiler Explorer which verifies that both this works with both GCC and clang. If you were to try to call dim2<dim1> where dim1 does not equal 2 or 3, then a compiler error complaining about backend<dim1>::dims not defined will be generated. You could add other members to the backend specializations, taking care to keep the names the same across the different values of dim1.
Total side note, why are you setting ar1 = {0};? From my reading of the std array reference, this would only set the first element in the array to 0.
I am Trying to explore partial specialization of templates in order to build a traits system. Unfortunately I cannot get the full thing working. I created the simplest model to show what does not work. It is not even clear to me whether I am trying something that is not supported (actually I see around examples of the same nature but the devil is in the details).
I am just creating a small example in which I have two enums and would like to create a string differently depending on the combination of the two. Of course this is just a dummy example to show the problem, the same thing in this case can be done in many other ways.
#ifndef TESTTRAITS_H_
#define TESTTRAITS_H_
#include <string>
using namespace std;
enum MovementType {
WALKS = 0, SWIMS = 1
};
enum AnimalType {
DOG = 0, CAT = 1, DOLPHIN = 2
};
template<AnimalType A, MovementType B>
struct movementAnimal {
static const string quality;
};
template<AnimalType A>
struct movementAnimal<A,WALKS> {
static const string quality;
};
template<AnimalType A>
struct movementAnimal<A,SWIMS> {
static const string quality;
};
#endif /* TESTTRAITS_H_ */
Now I write the assignment of the static variable
#include "TestTraits.h"
template<>
const string movementAnimal<DOLPHIN, WALKS>::quality = "Not capable";
template<>
const string movementAnimal<DOLPHIN, SWIMS>::quality = "Excellent";
template<AnimalType A>
const string movementAnimal<A, SWIMS>::quality = "Decent";
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
And a small main function
#include <iostream>
using namespace std;
#include "TestTraits.h"
int main() {
cout << movementAnimal<DOLPHIN,WALKS>::quality << endl;
cout << movementAnimal<DOG,WALKS>::quality << endl;
return 0;
}
If I compile I get the error:
/src/TestProject.cpp:15: undefined reference to `movementAnimal<(AnimalType)0, (MovementType)0>::quality[abi:cxx11]'
collect2: error: ld returned 1 exit status>
If I remove the reference to movementAnimal<DOG,WALKS>::quality then it compiles perfectly.
I get that it is not digesting the partial template specification
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
I do not know why and whether it is possible to have the pattern working.
As I can see, you put these definitions into separate files. The definition of the template classes is in TestTraits.h, but the definition of the static consts is somewhere else. The main CPP file includes just the TestTraits.h. That should sound like a good decision, but that doesn't work in the world of templates.
So, you have defined the enums and templates/partial specializations. Your main cpp module sees these definitions. Good. The compiler knows the template classes when it instantiates the walking dog here:
cout << movementAnimal<DOG,WALKS>::quality << endl;
Does the compiler see the definition of the static const? If it doesn't, the code like that is useless:
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
When the compiler sees the code above it cannot know all the values of A that you would use. So whenever you decide that the DOG WALKS, this instantiation point shall see the definition of const string movementAnimal<A, WALKS>::quality;
The solution is to ensure that the code from main function knows both definitions of template classes and the definitions of static consts.
There are two solutions. First is to put everything into one header file or to include both files from cpp file. Don't forget to include both.
The second solution is to have an explicit instantiation of some classes somewhere in your code:
template class movementAnimal<DOG, WALKS>;
Suppose there's a library, one version of which defines a function with name foo, and another version has the name changed to foo_other, but both these functions still have the same arguments and return values. I currently use conditional compilation like this:
#include <foo.h>
#ifdef USE_NEW_FOO
#define trueFoo foo_other
#else
#define trueFoo foo
#endif
But this requires some external detection of the library version and setting the corresponding compiler option like -DUSE_NEW_FOO. I'd rather have the code automatically figure what function it should call, based on it being declared or not in <foo.h>.
Is there any way to achieve this in any version of C?
If not, will switching to any version of C++ provide me any ways to do this? (assuming the library does all the needed actions like extern "C" blocks in its headers)? Namely, I'm thinking of somehow making use of SFINAE, but for a global function, rather than method, which was discussed in the linked question.
In C++ you can use expression SFINAE for this:
//this template only enabled if foo is declared with the right args
template <typename... Args>
auto trueFoo (Args&&... args) -> decltype(foo(std::forward<Args>(args)...))
{
return foo(std::forward<Args>(args)...);
}
//ditto for fooOther
template <typename... Args>
auto trueFoo (Args&&... args) -> decltype(fooOther(std::forward<Args>(args)...))
{
return fooOther(std::forward<Args>(args)...);
}
If you are statically linking to a function, in most versions of C++, the name of the function is "mangled" to reflect its argument list. Therefore, an attempt to statically link to the library, by a program with an out-of-date .hpp file, will result in an "unknown symbol" linker-error.
In the C language, there's no metadata of any kind which indicates what the argument list of any exported function actually is.
Realistically, I think, you simply need to be sure that the .h or .hpp files that you're using to link to a library, actually reflect the corresponding object-code within whatever version of that library you are using. You also need to be sure that the Makefile (or "auto-make" process) will correctly identify any-and-all modules within your application which link-to that library and which therefore must be recompiled in case of any changes to it. (If it were me, I would recompile the entire application.) In short, you must see to it that this issue doesn't occur.
In C++ you can do something like this:
#include <iostream>
#include <type_traits>
//#define DEFINE_F
#ifdef DEFINE_F
void f()
{
}
#endif
namespace
{
constexpr struct special
{
std::false_type operator()() const;
}f;
}
struct checkForF
{
static const constexpr auto value = std::conditional< std::is_same<std::false_type, decltype(::f())>::value, std::false_type, std::true_type >::type();
};
int main()
{
std::cout << checkForF::value << std::endl;
}
ideone
Please note I only handle f without any parameters.
Been away from C++ for a few years and am getting a linker error from the following code:
Gene.h
#ifndef GENE_H_INCLUDED
#define GENE_H_INCLUDED
template <typename T>
class Gene {
public:
T getValue();
void setValue(T value);
void setRange(T min, T max);
private:
T value;
T minValue;
T maxValue;
};
#endif // GENE_H_INCLUDED
Gene.cpp
#include "Gene.h"
template <typename T>
T Gene<T>::getValue() {
return this->value;
}
template <typename T>
void Gene<T>::setValue(T value) {
if(value >= this->minValue && value <= this->minValue) {
this->value = value;
}
}
template <typename T>
void Gene<T>::setRange(T min, T max) {
this->minValue = min;
this->maxValue = max;
}
Using Code::Blocks and GCC if it matters to anyone. Also, clearly porting some GA stuff to C++ for fun and practice.
The template definition (the cpp file in your code) has to be included prior to instantiating a given template class, so you either have to include function definitions in the header, or #include the cpp file prior to using the class (or do explicit instantiations if you have a limited number of them).
Including the cpp file containing the implementations of the template class functions works. However, IMHO, this is weird and awkward. There must surely be a slicker way of doing this?
If you have only a few different instances to create, and know them beforehand, then you can use "explicit instantiation"
This works something like this:
At the top of gene.cpp add the following lines
template class Gene<int>;
template class Gene<float>;
In if(value >= this->minValue && value <= this->minValue) the second minValue should be maxValue, no?
Echo what Sean said: What's the error message? You've defined and declared the functions, but you've not used them in anything anywhere, nor do I see an error (besides the typo).
TLDR
It seems that you need an Explicit Instantiation i.e. to actually create the class. Since template classes are just "instructions" on how to create a class you actually need to tell the compiler to create the class. Otherwise the linker won't find anything when it goes looking.
The thorough explanation
When compiling your code g++ goes through a number of steps the problem you're seeing occurs in the Linking step. Template classes define how classes "should" be created, they're literally templates. During compile time g++ compiles each cpp file individually so the compiler sees your template on how to create a class but no instructions on what "classes" to create. Therefore ignores it. Later during the linking step the g++ attempts to link the file containing the class (the one that doesn't exist) and fails to find it ultimately returning an error.
To remedy this you actually need to "explicitly instantiate" the class by adding the following lines to Gene.cpp after the definition of the class
template class Gene<whatever_type_u_wanna_use_t>;int
Check out these docs I found them to be super helpful.
I can't understand, why if we define static variable of usual (non-template) class in header, we have linker error, but in case of templates all works fine and moreover we will have single instance of static variable among all translation units:
It's template header (template.h):
// template.h
template<typename T>
class Templ {
public:
static int templStatic;
};
template<typename T> Templ<T>::templStatic = 0;
It's first unit using template (unit1.cpp)
// unit1.cpp
#include "template.h"
int method1() {
return Templ<void>::templStatic++;
}
Second unit here (unit2.cpp):
// unit2.cpp
#include "template.h"
int method2() {
return Templ<void>::templStatic++;
}
And, finally, main.cpp:
// main.cpp
#include <iostream>
int method1();
int method2();
int main(int argc, char** argv) {
std::cout << method1() << std::endl;
std::cout << method2() << std::endl;
}
After compilling, linking and executing this code, we will have following output:
0
1
So, why in case of templates all works fine (and as expected) ? How compiler or linker handle this (we can compile each .cpp file in separated calling of compiler, and then link them with caling to linker, so compiler and linker don't "see" all .cpp files at same time) ?
PS: My compiler: msvcpp 9 (but checked on mingw too)
It's because the definition of the static data member is itself a template. Allowing this is necessary for the same reason you are allowed to have a function template that's not inline multiple times in a program. You need the template to generate the resulting entity (say, a function, or a static data member). If you wouldn't be allowed to put the definition of a static data member, how would you instantiate the following
template<typename T>
struct F {
static int const value;
};
template<typename T>
int const F<T>::value = sizeof(T);
It's not known what T is - the Standard says the definition outside the class template is a template definition, in which the parameters are inherited from its class template owner.
I've made some experiment with GCC. In the following, we have one implicit instantiation of F<float>::value, and one explicit specialization of F<char>::value which has to be defined in a .cpp file to not cause duplicated symbol errors when included multiple times.
// Translation Unit 1
template<typename T>
struct F {
static int value;
};
template<typename T>
int F<T>::value = sizeof(T);
// this would belong into a .cpp file
template<> int F<char>::value = 2;
// this implicitly instantiates F<float>::value
int test = F<float>::value;
int main() { }
The second translation unit contains just another implicit instantiation of the same static data member
template<typename T>
struct F {
static int value;
};
template<typename T>
int F<T>::value = sizeof(T);
int test1 = F<float>::value;
Here is what we get with GCC - it makes each implicit instantiation into a weak symbols and sticks it into its own section here. Weak symbols will not cause errors when there exist multiple of them at link time. Instead, the linker will choose one instance, and discards the other ones assuming all of them are the same
objdump -Ct main1.o # =>
# cut down to the important ones
00000000 l df *ABS* 00000000 main1.cpp
0000000a l F .text 0000001e __static_initialization_and_destruction_0(int, int)
00000000 l d .data._ZN1FIfE5valueE 00000000 .data._ZN1FIfE5valueE
00000028 l F .text 0000001c global constructors keyed to _ZN1FIcE5valueE
00000000 g O .data 00000004 F<char>::value
00000000 g O .bss 00000004 test
00000000 g F .text 0000000a main
00000000 w O .data._ZN1FIfE5valueE 00000004 F<float>::value
So as we can see F<float>::value is a weak symbol which means the linker can see multiple of these at link time. test, main and F<char>::value are global (non-weak) symbols. Linking main1.o and main2.o together, we see in the map output (-Wl,-M) the following
# (mangled name)
.data._ZN1FIfE5valueE
0x080497ac 0x4 main1.o
0x080497ac F<float>::value
This indicates that actually it drops all except one instance.
There is solution, you can create a parent class and put the static variable in it, then make your template class inherit it privately, here's an example:
class Parent
{
protected:
static long count;
};
long Parent::count = 0;
template<typename T>
class TemplateClass: private Parent
{
private:
int mKey;
public:
TemplateClass():mKey(count++){}
long getKey(){return mKey;}
}
int main()
{
TemplateClass<int> obj1;
TemplateClass<double> obj2;
std::cout<<"Object 1 key is: "<<obj1.getKey()<<std::endl;
std::cout<<"Object 2 key is: "<<obj2.getKey()<<std::endl;
return 0;
}
Output will be:
Object 1 key is: 0
Object 2 key is: 1
It's because template code is not source code; it's instructions on how to write source code.
The non-template static variable is actual source code, and the compiler will attempt to do exactly what you say by including something in twice. Hence, you have to initialize the static variable in a .cpp file, and only reference it in the .h file describing the class. It's equivalent to a global variable declared through extern.
When the compiler sees
template<class T> Templ{...};
it does nothing except make a note that the template exists. As far as it is concerned, there is no source code associated with Templ.
The first time you actually refer to
Templ<int> Instance
the compiler looks at all the template<> code associated with Templ and uses it to construct a .h and a .cpp file (which exists only for the duration of compilation). Those files might look like this:
Temple_int.h
class Templ_int{
public:
static int templStatic;
};
Templ_int.cpp
#include "Templ_int.h"
Templ_int::templStatic = 0;
And every
Templ<int>
becomes a Templ_int.
Thus, the source code to initialize the static variable only exists once, in a .cpp file created by the compiler.
(Obviously, the actual compiler-specific implementation of this process would be robust against creating a class with a similar name to the template, etc.)