I am new to C++ and am having difficulties resolving an Undefined Reference problem that I am running into. I am trying to create a test class that takes as input an array into a constructor, and everything seems to work if I have everything located in one file as below:
main.cpp
#include <iostream>
class Test
{
public:
template<typename T,int SIZE>
Test(T (&array)[SIZE]);
};
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
int main()
{
int myIntArray[10];
Test myTest(myIntArray);
return 0;
}
When I run this example, I get the following output:
Array constructor was called
Size of array is: 10
However, when I break this example up into the following three files:
Test.h
class Test
{
public:
template<typename T,int SIZE>
Test(T (&array)[SIZE]);
};
Test.cpp
#include "Test.h"
#include <iostream>
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
main.cpp
#include "Test.h"
#include <iostream>
int main()
{
int myIntArray[10];
Test myTest(myIntArray);
return 0;
}
I receive an undefined reference to Test::Test<int, 10>(int (&) [10])'. I am not exactly sure what I am doing incorrectly and am thinking that perhaps I am overlooking something. Any insight would be appreciated. Thank you for the help.
The problem is you are seperating out your template function declaration and template function definition. When you define a template function, your declaration of the function and its definition must be co-located. If not co-located, you should define your template function in a .tpp file and then include that .tpp file in the header file where your template function is declared.
Why is this required? Unlike your normal functions, where the type of the parameters is known beforehand, the compiler loads one version of the template function for every invocation of the function with a different type. So, in your case, when you do,
int main()
{
int myIntArray[10];
Test myTest(myIntArray);
return 0;
}
What the compiler does is, define a function definition,
Test::Test(int (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
and load this into memory.
However, if the compiler has to do this, it has to have access to the definition of the function when it tries to look over the declaration in the header file. When you put the defintion of the function in a seperate .cpp file, the compiler does not have access to the definition of the function and hence cannot define and load the function into memory based on the user input.
Like I mentioned, if you want to seperate out the implementation from the definition, you can put the definition of the template function in a .tpp(which is a specialized file for template function definitions) file and include that in your .h. Something like this.
Test.h :
class Test
{
public:
template<typename T,int SIZE>
Test(T (&array)[SIZE]);
};
#include "Test.tpp"
Test.tpp
#include <iostream>
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
main.cpp
#include <iostream>
template<typename T,int SIZE>
Test::Test(T (&array)[SIZE])
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
Hope this helps.
Try this:
main.cpp
#include <iostream>
template<typename T>
class Test
{
public:
Test(T *array, int SIZE)
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
};
Test.h
#include <iostream>
template<typename T>
class Test
{
public:
Test(T *array, int SIZE)
{
std::cout << "Array constructor was called" << std::endl;
std::cout << "Size of array is: " << SIZE << std::endl;
}
};
You probably want to use a std::vector instead of arrays. This way you do not always have to reference the size of the array before you use it. It is much easier to manage.
Additionally, template classes are better off implemented in their header file.
Related
Consider this snippet:
struct A {
template <typename T> void bar(const T &) {
/*
I would like to write something like:
if constexpr(type T already processed/T is already present in typelist)
...do something fancy
else if constexpr(type T not processed/T is not present in typelist)
*/
}
};
struct Msg1 {};
struct Msg2 {};
int main() {
A a;
a.bar(Msg1{});
a.bar(Msg1{});
}
Demo
Is it possible to see at compile time for which types the method bar was already instantiated?
Ideally, there would be some kind of growing typelist, where one can check at compile time for which types bar is already instantiated.
No. It is not possible to do so at compile time. However, it would be possible to do the following at runtime:
#include <typeindex>
#include <type_traits>
#include <unordered_set>
struct A {
private:
std::unordered_set<std::type_index> already_processed_ts;
public:
template<typename T>
void bar(const T&){
if(already_processed_ts.find(typeid(T)) != already_processed_ts.end())
std::cout << "Already processed " << typeid(T).name() << std::endl;
else{
already_processed_ts.insert(typeid(T));
std::cout << "Processing " << typeid(T).name() << "... \n";
}
}
}
struct Msg{};
int main()
{
f(Msg{}); // Prints "Processing 3Msg..." (at least on my compiler)
f(Msg{}); // Prints "Already processed 3Msg"
return 0;
}
i have this piece of code (http://coliru.stacked-crooked.com/a/ee05a00fc8ab5057):
#include <type_traits>
struct unregistered;
unregistered register_type(...);
template<class T>
constexpr bool is_registered = !std::is_same_v<unregistered, decltype(register_type(std::declval<T>()))>;
template<class T>
struct test_registration
{
static_assert(is_registered<T>, "Type is not registered!");
};
struct foo{};
struct bar{};
void register_type(int);
void register_type(char);
void register_type(void*);
void register_type(foo);
void register_type(foo*);
#include <boost/core/demangle.hpp>
#include <iostream>
int main()
{
std::cout << boost::core::demangle(typeid(test_registration<foo>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<foo*>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<int>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<char>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<void*>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<long>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<bar>).name()) << "\n";
return 0;
}
The compiler generates errors for the calls using int, char, void*, long and bar.
I expect the errors for long and bar.
What I do not understand is:
Why are int, char, and foo treated differently?
Why are void*, and foo* treated differently? (both are ptrs)
I assume the reason has to do with foo beeing class type and int and char beeing plain types.
I would like to know the reason. Is it a compiler bug or is there some passage in the standard explaining this behaviour?
What I am asking is not how I can fix this problem (see link to coliru for a fix).
What I want to know is why it is behaving like this.
i have a relatively small c++ project and i decided to make a Utils header file which would just contain some small helper functions etc. It was all working fine when i was declaring functions that were using a template, then i tried to make a function which didnt need a template, and suddently it doesn't work.
The result i get is a linker error; already defined in (file).obj
I cannot even declare a simple void function, everything without template gives a linker error.
I have NO IDEA whatsoever what could be causing this. Here is the code for the header file... Thanks in advance.
#pragma once
namespace Utils
{
std::string GetActiveWindowTitle()
{
// This doesnt work either, also gives linker error.
return active_window;
}
template<typename T>
void Print(char * value, T printValue)
{
std::cout << value << ": " << printValue << std::endl;
}
template<typename T>
void Print(T printValue)
{
std::cout << "DEBUG: " << printValue << std::endl;
}
void PrintStr(std::string str)
{
// This doesn't work because it doesnt have the template, it gives a linker error
std::cout << "DEBUG: " << str.c_str() << std::endl;
}
}
A function-template is implicitly inline. Thus, when defined in a header file, it doesn't violate ODR (One Definition Rule). For non-template functions in header files, you should either define them as inline, or define them in a separate translation unit.
So, you could do:
#pragma once
namespace Utils
{
inline std::string GetActiveWindowTitle()
{
return active_window;
}
template<typename T>
void Print(char * value, T printValue)
{
std::cout << value << ": " << printValue << std::endl;
}
template<typename T>
void Print(T printValue)
{
std::cout << "DEBUG: " << printValue << std::endl;
}
inline void PrintStr(std::string str)
{
std::cout << "DEBUG: " << str.c_str() << std::endl;
}
}
See Inline keyword vs header definition
If you include your header to more than one cpp, the function will be defined more than once and the linker will give you the error described above. See What is the difference between a definition and a declaration? or What are forward declarations in C++?
I'm trying to do separate compilation of my non-type argument template, but I am facing a few problems. My application has a number of opcodes, and each opcode is associated with certain data and functions, many of which are similar and could be defined in the primary template, then the differences can be put into specialized templates.
So here is the original in-line code:
(header)
#include <iostream>
template<int opcode>
class BAR
{
public:
BAR(){};
void foo()
{
std::cout << "BAR<int>::foo()" << std::endl;
}
};
// specialize 1 and 2, otherwise we go with the
// primary definition.
template <>
void BAR<1>::foo()
{
std::cout << "BAR<1>::foo()" << std::endl;
}
template <>
void BAR<2>::foo()
{
std::cout << "BAR<2>::foo()" << std::endl;
}
I have a simple 'main':
int main(int argc, char* argv[])
{
BAR<1> bar_1;
BAR<2> bar_2;
BAR<3> bar_3;
bar_1.foo();
bar_2.foo();
bar_3.foo();
return 0;
}
I managed to put the specializations for '1' and '2' into a cpp file and this is
what I have:
(header)
#include <iostream>
template<int opcode>
class BAR
{
public:
BAR(){};
void foo()
{
std::cout << "BAR<int>::foo()" << std::endl;
}
};
// specialize 1 and 2, otherwise we go with the
// primary definition.
template<> void BAR<1>::foo() ;
template<> void BAR<2>::foo() ;
(cpp)
#include "Foo.h"
#include <iostream>
template<> void BAR<1>::foo()
{
std::cout << "BAR<1>::foo()" << std::endl;
}
template<> void BAR<2>::foo()
{
std::cout << "BAR<2>::foo()" << std::endl;
}
void x()
{
BAR<1> b1;
BAR<2> b2;
b1.foo();
b2.foo();
}
I not real crazy about the x() function, but without this I get unresolved symbols for BAR<1>::foo() & BAR<2>::foo(), if there's a better way, I'd be interested ( MSVC 13 compiler).
Ok so far so good. I really want to put the primary definition of the function foo() into the CPP, but I can't seem to get the syntax right:
template<> void BAR<int>::foo()
{
std::cout << "BAR<int>::foo()" << std::endl;
}
this is not allowed by the compiler, and rightly so I guess, is not
a valid non-type value. So what is the magic words to use to do this?
Many thanks in advance for any help.
dave.
I'm looking for 'best-practice' in the following situation:
In general, there are three common ways to share private data between two (or more) non-member functions with differential advantages and disadvantages:
// Example 1: using 'static' class
// HPP
namespace foo {
class bar
{
private:
static const char* const s_private;
bar();
public:
static void s_method0();
static void s_method1();
}; /* class bar */
} /* namespace foo */
// CPP
namespace foo {
const char* const bar::s_private = "why do I need to be visible in HPP?";
void bar::s_method0() { std::cout << "s_method0 said: " << s_private << std::endl; }
void bar::s_method1() { std::cout << "s_method1 said: " << s_private << std::endl; }
} /* namespace foo */
// Example 2: using unnamed-namespace
// HPP
namespace foo {
void bar0();
void bar1();
} /* namespace foo */
// CPP
namespace foo {
namespace {
const char* const g_anonymous = "why do I need external linkage?";
} /* unnamed-namespace */
void bar0() { std::cout << "bar0 said: " << g_anonymous << std::endl; }
void bar1() { std::cout << "bar1 said: " << g_anonymous << std::endl; }
} /* namespace foo */
// Example 3: using static keyword in namespace-scope
// HPP
namespace foo {
void bar0();
void bar1();
} /* namespace foo */
// CPP
namespace foo {
static const char* const g_internal = "nobody outside this file can see me and I don't have external linkage";
void bar0() { std::cout << "bar0 said: " << g_internal << std::endl; }
void bar1() { std::cout << "bar1 said: " << g_internal << std::endl; }
} /* namespace foo */
I prefer 'Example 3' because it's as close to the intention as it could be.
But now I'm running in some problem's using templated functions. 'Example 1' seems to be the only way to solve this:
// HPP
namespace foo {
class bar
{
private:
static const char* const s_private;
bar();
public:
template<typename T> static void s_method0() { std::cout << "s_method0 said: " << s_private << std::endl; }
template<typename T> static void s_method1() { std::cout << "s_method1 said: " << s_private << std::endl; }
}; /* class bar */
} /* namespace foo */
// CPP
namespace foo {
const char* const bar::s_private = "why do I need to be visible in HPP?";
} /* namespace foo */
That's unsatisfying. Especialy because there are other (in this case methods) non-member function which should be in the same (in this case class-) scope, which don't need to access this private data.
Does anybody know an elegant solution?
Thanks for any help.
Best regards.
This is, somewhat unfortunately, an issue that springs quite often with template.
But may I suggest that you are over-engineering here ?
The truth is, whether you look at Loki code (by Andrei Alexandrescu) or Boost code (infamous David Abrahams notably), no-one really bothered to provide a better privacy.
Rather, they simply relied on convention and used a Private namespace (Loki) or a detail namespace (Boost, with sometimes a longer and more descriptive name to prevent clashes).
It's annoying, but there is not much you can do in practice.... though I actually have a solution for your specific problem ;)
// Evil solution!
#ifdef MY_SUPER_MACRO
# error "MY_SUPER_MACRO is already defined!"
#endif
#define MY_SUPER_MACRO "Some string"
template <typename T> void foo() { std::cout << "foo - " MY_SUPER_MACRO "\n"; }
template <typename T> void bar() { std::cout << "bar - " MY_SUPER_MACRO "\n"; }
#undef MY_SUPER_MACRO
And hop, I achieved locality in a header with an evil macro :)
If I understand correctly, your complaint/concern is that unlike with templates, with non-templates, one can define the function bodies inside the CPP, rather than the header, in which case they can access non-class statics, which are "invisible" to the outside world, including member functions defined in the header. This is all true.
However, remember that there's nothing stopping one defining other member functions in the CPP as well, in which case, they'd be equally able to access the static data. So really, the situation is no different. Your complaint is based on a false dichotomy.
If you genuinely want to prevent anything but s_method0<T>() and s_method1<T>() accessing s_private, then you must put them all in a dedicated class. It's as simple as that. This would be the case even for non-templates.
I had played around with the different techniques. My idea, using the unnamed namespace in the header file, was to 'mark' the 'shared'-classes as 'header-file-only'. Sure, due to the fact they aren't containing public members you cannot make nasty things anyway with it. But I thought it would be more close to the intention.
But I was wrong! After thinking about this I'm in shame. It's so logically simple. This example is showing what's the problem with it (entire code for clearness):
// header0.hpp
#ifndef HPP_HEADER0_INCLUDED
#define HPP_HEADER0_INCLUDED
#include <iostream>
#include <string>
namespace ns {
template<typename T> void header0_func0();
template<typename T> void header0_func1();
namespace {
class header0
{
template<typename> friend void ns::header0_func0();
template<typename> friend void ns::header0_func1();
static std::string s_private;
}; /* class header0 */
} /* unnamed */
template<typename T> void header0_func0() { std::cout << "header0_func0: " << header0::s_private << std::endl; }
template<typename T> void header0_func1() { std::cout << "header0_func1: " << header0::s_private << std::endl; }
} /* namespace ns */
#endif /* HPP_HEADER0_INCLUDED */
// header1.hpp
#ifndef HPP_HEADER1_INCLUDED
#define HPP_HEADER1_INCLUDED
#include <iostream>
#include <string>
namespace ns {
template<typename T> void header1_func0();
template<typename T> void header1_func1();
namespace {
class header1
{
template<typename> friend void ns::header1_func0();
template<typename> friend void ns::header1_func1();
static std::string s_private;
}; /* class header1 */
} /* unnamed */
template<typename T> void header1_func0() { std::cout << "header1_func0: " << header1::s_private << std::endl; }
template<typename T> void header1_func1() { std::cout << "header1_func0: " << header1::s_private << std::endl; }
} /* namespace ns */
#endif /* HPP_HEADER1_INCLUDED */
// source.cpp
#include "header0.hpp"
#include "header1.hpp"
std::string ns::header0::s_private = "header0 private data definition by source.cpp",
ns::header1::s_private = "header1 private data definition by source.cpp";
namespace {
// hide private class
class source
{
source();
~source();
static source s_instance;
};
source::source() {
std::cout << "source.cpp:\n";
ns::header0_func0<int>();
ns::header0_func1<int>();
ns::header1_func0<int>();
ns::header1_func1<int>();
std::cout << '\n';
}
source::~source() { }
source source::s_instance;
} /* unnamed */
By now everything seems to be OK. But what happen's if we try to use our headers in other translation units? Let's take a look:
// main.cpp
#include "header0.hpp"
#include "header1.hpp"
int main()
{
std::cout << "main.cpp:\n";
ns::header0_func0<int>();
ns::header0_func1<int>();
ns::header1_func0<int>();
ns::header1_func1<int>();
std::cout << '\n';
return 0;
}
What happens is, that we are ending with 2 unresolved externals. So, is the linker just an idiot? No, he is not. Thinking about what are unnamed namespace used for, we know what's going on. An unnamed namespace has an unique identifier in each translation unit. Thus, in our main.cpp, the linker doesn't know the definition of our private data in source.cpp.
So, what happens if we define this private data in main.cpp - just to bring matters to a head - ?
// main.cpp
#include "header0.hpp"
#include "header1.hpp"
std::string ns::header0::s_private = "header0 private data definition by main.cpp",
ns::header1::s_private = "header1 private data definition by main.cpp";
int main()
{
std::cout << "main.cpp:\n";
ns::header0_func0<int>();
ns::header0_func1<int>();
ns::header1_func0<int>();
ns::header1_func1<int>();
std::cout << '\n';
return 0;
}
Now, everything is compiling and getting linked 'correctly' - or rather, it seems so.
This is the console output of that program:
source.cpp:
header0_func0: header0 private data definition by source.cpp
header0_func1: header0 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
main.cpp:
header0_func0: header0 private data definition by source.cpp
header0_func1: header0 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
That means: If undefined behavior is what you are looking for, here you are.
In other words: Based on the explanation above: Don't use unnamed namespace in header files to encapsulate private shared data.
And the last question is, "what's the solution?"
If you don't want to use 'static' (utility) classes, you should prefer my first posted solution (only changed code):
// header0.hpp
// ...
namespace ns {
// ...
namespace detail {
class header0 { /*...*/ };
} /* namespace detail */
template<typename T> void header0_func0() { std::cout << "header0_func0: " << detail::header0::s_private << std::endl; }
template<typename T> void header0_func1() { std::cout << "header0_func1: " << detail::header0::s_private << std::endl; }
} /* namespace ns */
// ...
// header1.hpp
// ...
namespace ns {
// ...
namespace detail {
class header1 { /*...*/ };
} /* namespace detail */
template<typename T> void header0_func0() { std::cout << "header0_func0: " << detail::header1::s_private << std::endl; }
template<typename T> void header0_func1() { std::cout << "header0_func1: " << detail::header1::s_private << std::endl; }
} /* namespace ns */
// ...
// source.cpp
// ...
std::string ns::detail::header0::s_private = "header0 private data definition by source.cpp",
ns::detail::header1::s_private = "header1 private data definition by source.cpp";
// ...
I'm looking forward to any comment. Best regards.
What about that?
namespace foo {
namespace detail {
class shared
{
template<typename> friend void bar0();
template<typename> friend void bar1();
static const char* const m_private;
}; /* class shared */
} /* namespace detail */
template<typename T> void bar0() { std::cout << "bar0 said: " << detail::shared::m_private << std::endl; }
template<typename T> void bar1() { std::cout << "bar1 said: " << detail::shared::m_private << std::endl; }
} /* namespace foo */
EDIT 2:
OBSOLETE ANSWER. THIS CODE ISN'T WORKING! POSTED AN EXPLANATION BELOW.
EDIT:
In 'real code' I would replace namespace detail by an unnamed namespace. This would bring up the possibility to add other shared resources in different header files using the same name-scope:
namespace foo {
template<typename T> void bar0();
template<typename T> void bar1();
template<typename T> void bar2();
template<typename T> void bar3();
namespace {
class shared0
{
template<typename> friend void foo::bar0();
template<typename> friend void foo::bar1();
static const char* const m_private0;
}; /* class shared0 */
class shared1
{
template<typename> friend void foo::bar2();
template<typename> friend void foo::bar3();
static const char* const m_private1;
}; /* class shared1 */
} /* unnamed */
template<typename T> void bar0() { std::cout << "bar0 said: " << shared0::m_private0 << std::endl; }
template<typename T> void bar1() { std::cout << "bar1 said: " << shared0::m_private0 << std::endl; }
template<typename T> void bar2() { std::cout << "bar0 said: " << shared1::m_private1 << std::endl; }
template<typename T> void bar3() { std::cout << "bar1 said: " << shared1::m_private1 << std::endl; }
} /* namespace foo */