I have an object like the following
template<typename T>
inline void UnusedParameter( T const& )
{
}
class Client
{
public:
template<class T>
void runFFT(T *wSamples, float const &fMult)
{
std::cout << "INSIDE RUNFFT : : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
};
And in my CPP I have the following:
#include "object.hpp"
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult)
{
std::cout << "INSIDE INT16_T version: : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult)
{
std::cout << "INSIDE IPP32F version: : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
Both these implementation run without any problem in my Debug Code. It enters the int16_t version without problem and the Ipp32f version also without problem.
But when I try the Run version it only enters the Template, like the compiler only compiles the Template implementation in the header.
How do I prevent this from happenning? Shall I remove this and just create two different methods? I love my templates but these Heisenberg bugs are frustating.
Thanks for any input.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Andy Prowl answered this question and it is solved doing the following in the HPP:
template<typename T>
inline void UnusedParameter( T const& )
{
}
class Client
{
public:
template<class T>
void runFFT(T *, float const &)
{
// Thanks for Joachim for removing my Unused Parameter crap
std::cout << "INSIDE RUNFFT : : :" << std::endl;
}
};
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult);
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult);
And now it works in runtime as well. The CPP stays the same.
The problem is most likely in the fact that you relegated the specializations of your member function runFFT() for int16_t and Ipp32f in a separate .cpp file without providing a corresponding declaration after the primary template, so the compiler at the point of instantiation (which likely belongs to another translation unit that #includes only the header file containing the definition of Client) doesn't know about the existence of those explicit specializations.
Put a declaration for those specializations in the same header file that contains the definition of your class template:
template<typename T>
inline void UnusedParameter( T const& ) { }
class Client
{
public:
template<class T>
void runFFT(T *wSamples, float const &fMult)
{
std::cout << "INSIDE RUNFFT : : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
};
// DECLARE YOUR EXPLICIT SPECIALIZATIONS HERE
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult);
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult);
Per Paragraph 14.7.3/6 of the C++11 Standard:
If a template, a member template or a member of a class template is explicitly specialized then that specialization
shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required. [...]
The "no diagnostic is required" part means that if you don't follow this rule, your program will be ill-formed, but your compiler/linker is not required to tell you. This normally results in the kind of undefined behavior you are observing.
Related
I'm learning some new concepts about c++ and I'm playing with them.
I wrote some piece of code that really confuses me in terms of how it works.
#include <iostream>
class aid {
public:
using aid_t = std::string;
void setaid(const std::string& s) {
aid_ = s;
}
const aid_t& getaid() const {
return aid_;
}
private:
aid_t aid_;
};
class c {
public:
using c_t = std::string;
void setc(const aid::aid_t& aid_val) {
if (aid_val.size() < 4)
c_ = "yeah";
else
c_ = aid_val + aid_val;
}
const c_t& getc() {
return c_;
}
private:
c_t c_;
};
template<typename ...Columns>
class table : public Columns... {
};
template <typename... Columns>
void f(table<Columns...>& t) {
t.setaid("second");
std::cout << t.getaid() << "\n";
}
void f2(table<aid>& t) {
t.setaid("third");
std::cout << t.getaid() << "\n";
}
int main() {
table<aid, c> tb;
tb.setaid("first");
std::cout << tb.getaid() << " " << "\n";
// f<c>(tb); // (1) doesnt compile, that seem obvious
f<aid>(tb); // (2) works?
f(tb); // (3) works too -- template parameter deduction
// f2(tb); // (4) doesnt work? worked with (2)...
}
The idea here is simple, I have some table with columns. And then I would like to create some functions that require only some set of columns and doesn't care if passed argument has some extra columns.
My confusion is mostly about points (2) and (4) in code... My intuition says it should be the same, why it isn't and (2) compiles and (4) doesn't? Is there any major topic I'm missing and should read up?
Is there a way to achieve this particular functionality?
In the second case, the compiler still deduces the rest of the template parameter pack, so that you get table<aid, c> & as the function parameter. This is different from (4) (table<aid> &).
[temp.arg.explicit]/9:
Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments.
Is it possible to recognize all calling of a certain function in everywhere
function1<T1>(); function1<T4>(); ...
then add a line that calling this following line in a certain place?
function2<T1>(); function2<T4>(); ...
For example,
class X{
template <class T> function1(){ }
template <class T> function2(){ }
}
class A{}
class B{}
class C{}
int main(){
X x;
//vvvv this code (hopefully) will be auto generated (by macro?)
x.function2<A>();
x.function2<B>(); //<--- I don't care about order of A or B
//x.function2<C>(); //<--- this line should not be generated
//^^^^ Only X's function1 should be recognized,
// not other class's functions with the same name.
x.function1<B>();
x.function1<A>();
x.function1<B>(); .... // called in various places in many .cpp
//If it is called in another .cpp, but not here, it should still be recognized
}
Edit
My old code call :-
function2<T>() inside function1<T>()
It costs CPU significantly (I profiled), because function1 have to check whether function2 was called or not every time.
Here is a draft of a near-zero overhead solution that will work only if you are not going to invoke function1() before main():
#include <iostream>
#include <typeinfo>
template <class T>
void function2()
{
std::cout << "function2<" << typeid(T).name() << ">()" << std::endl;
}
bool dummy = true;
template <class T>
struct Func1WasInstantiated
{
struct CallFunc2
{
CallFunc2() { function2<T>(); }
void operator()() const { dummy = false; }
};
static CallFunc2 callFunc2;
};
template <class T>
typename Func1WasInstantiated<T>::CallFunc2 Func1WasInstantiated<T>::callFunc2;
template <class T>
void function1()
{
Func1WasInstantiated<T>::callFunc2();
std::cout << "function1<" << typeid(T).name() << ">()" << std::endl;
}
int main()
{
std::cout << "------- Entered main() ---------" << std::endl;
function1<int>();
function1<double>();
function1<int>();
return 0;
}
Output (check it on IDEONE):
function2<i>()
function2<d>()
------- Entered main() ---------
function1<i>()
function1<d>()
function1<i>()
The global variable dummy is the acceptor of the side effect, that ensures that Func1WasInstantiated<T>::callFunc2 is linked into the program and makes the code work as intended. Without the side effect contained in callFunc2() I can imagine an aggressively optimizing compiler eliminating that line from function1() (that is normal) and letting the linker leave out the callFunc2 objects as they become unreferenced (I cannot judge whether this would be against the C++ standard or not).
Experimenting with trailing return types and tag dispatching, I have written the following code.
#include <string>
#include <iostream>
using namespace std;
namespace Params
{
struct t_param1{};
struct t_param2{};
};
template<typename t_detail>
struct Select;
template<>
struct Select<Params::t_param1> {using choice = Params::t_param1;};
template<>
struct Select<Params::t_param2> {using choice = Params::t_param2;};
class Tester
{
private:
using t_uint32 = uint32_t;
using t_string = string;
private:
t_uint32 m_param1;
// t_string m_param2;
private:
template<typename t_entity>
void assign(const Params::t_param1&, t_entity&& entity);
template<typename t_entity>
void assign(const Params::t_param2&, t_entity&& entity);
auto access(const Params::t_param1&) -> decltype(m_param1);
// auto access(const Params::t_param2&) -> decltype(m_param2);
public:
template<typename t_detail, typename t_entity>
void assign(t_entity&& entity);
template<typename t_detail>
auto access() -> decltype(access(typename Select<t_detail>::choice()));
};
template<typename t_detail, typename t_entity>
void
Tester::assign(t_entity&& entity)
{
assign(typename Select<t_detail>::choice(), entity);
}
template<typename t_entity>
void
Tester::assign(const Params::t_param1&, t_entity&& entity)
{
m_param1 = entity;
cout << "Assigned m_param1 with " << entity << endl;
}
/*
template<typename t_entity>
void
Tester::assign(const Params::t_param2&, t_entity&& entity)
{
m_param2 = entity;
cout << "Assigned m_param2 with " << entity << endl;
}
*/
template<typename t_detail>
auto
Tester::access()
-> decltype(access(typename Select<t_detail>::choice()))
{
return(access(typename Select<t_detail>::choice()));
}
auto
Tester::access(const Params::t_param1&)
-> decltype(m_param1)
{
return(m_param1);
}
/*
auto
Tester::access(const Params::t_param2&)
-> decltype(m_param2)
{
return(m_param2);
}
*/
int main() {
auto tester = Tester();
tester.assign<Params::t_param1>(79);
// tester.assign<Params::t_param2>("viziv");
auto param1 = tester.access<Params::t_param1>();
// auto param2 = tester.access<Params::t_param2>();
cout << "Access: param1 = " << param1 << endl;
// cout << "Access: param2 = " << param2 << endl;
return 0;
}
when I compile this code using Apple LLVM version 7.0.2 (clang-700.1.81), I get the following compilation error
junk1.cpp:78:9: error: out-of-line definition of 'access' does not match any declaration in 'Tester'
Tester::access()
^~~~~~
1 error generated.
Curiously, when I uncomment the code to assign and access param2 (commented out in the above code), it compiles fine and produces the required result.
What am I doing wrong? Could anyone please explain to me why the inclusion of param2 change in compilation behaviour?
I think there is one and a half issues going on here.
The first lies in that using a trailing return type essentially creates a templated function. When you attempt to use a class' function, the class type must not be incomplete.
That is why moving the function definition for the public access method into the class declaration fixes it (Demo); the class is otherwise incomplete so long as the public access method hasn't been defined, and that method cannot be defined until the class is complete.
Note that another way to fix this would be if the private version of access were somehow a non-member function (e.g., a free-floating function in the surrounding scope).
The problem with that approach (half of a problem, because you're not actually trying to do this) is that, trying to call the now-free floating version of access requires the compiler to evaluate all possible overloads, including the public templated access (Thanks to ADL). When that happens, Select<t_detail>::choice is evaluated in a non-deduced context, and the actual underlying type cannot be obtained.
So, if we both moved the private access outside of Tester and renamed it (to something like access2), then we are allowed to separate the declaration and the definition of the public access function (Demo)
my goal is to make a class containing a tuple consisting of classes all of which have a method void update() which allows all the contained update() methods to be called in a row with minimal overhead. Here is my code:
template< typename... Tel >
class ExecSet
{
private:
std::tuple<Tel...> m_data;
//Compile-time Recursive
template<int _iter, typename _Head, typename... _Tail>
inline void _update()
{
std::get<_iter>(m_data).update();
_update< _iter + 1, _Tail... >();
}
//Base case
template<int _iter>
inline void _update()
{
//Do nothing here
}
public:
inline void update()
{
_update<0, Tel...>();
}
};
class Foo
{
//..
inline void update()
{
std::cout << "An update of Foo " << m_i << "\n";
}
private:
int m_i;
};
class Bar
{
//..
inline void update()
{
std::cout << "An update of Bar " << m_i << "\n";
}
private:
int m_i;
};
The code compiles and a test executes as expected. My question is, can I be 100% sure that ExecSet::update() will be completely inlined along with every recursed call made inside? I would imagine it should because this is all determined at compile time. And under -O3 everything should be inlined too right?
No, you cannot. C++ standard does not guarantee function to be inlined even if you add inline specifier.
You can ask the compiler to emit symbolic assembly instead of machine code and check for yourself. That said, having done just that on multiple occasions myself, I'm sure no serious compiler would leave such a mundane opportunity to inline unused. The things modern compilers do, they are pure magic.
This is kind of a follow on to this question.
#include <iostream>
struct type1 {};
struct type2 {};
void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<type1>();
bar<type2>();
return 0;
}
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
In the above code foo(type2) is not visible at the time of instantiation of bar<type2> in main. And yet the code compiles and produces the following output :
foo(type1)
foo(type2)
How does the compiler know that foo(type2) is available when instantiating bar<type2> in main?
EDIT : I am trying to understand more about how overload resolution during template instantiation works. Consider the code below :
#include <iostream>
struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};
void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
int main()
{
foo(type3());
return 0;
}
void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}
The output is
foo(type2)
Even though a closer match foo(type3) is available, the call foo(type3()) resolves to foo(type2) because that was the only candidate that has been parsed by the compiler until that point. Now consider the following code :
#include <iostream>
struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<type3>();
return 0;
}
void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}
The output is
foo(type3)
That is, at the point of the call bar<type3>(), even though only foo(type2) is visible, the compiler still picks foo(type3) that comes later because that is a closer match.
Any symbol left without a definition is to be replaced during the linking process, since the function foo(type2) could've been provided in another file.
The compiler is to say whether the function needed has been defined by the end of the entire process, when no further substitution can be applied.
In order to clarify the understanding, you must be aware of the steps required to compile, say, a common C program:
first, you expand all the macros on your code;
then your code is validated according to the language syntax, so that it can be converted into assembly language -- the compilation process itself; during this step, every symbol found without a definition is annotated in a table with the entries (symbol, definition), that shall be completed later, allowing your program to be constructed properly;
next, your code compiled into assembly will be converted to machine language, i.e., the objects will be created;
finally, you need to link your already executable objects, in order to solve any dependencies on symbol definitions; this last step checks your objects for undefined symbols, adding definitions from other modules or from libraries, thus, completing the program.
If any symbol was not correctly "linked" to its definition, the compiler will point out an error in your program -- the classic undefined reference to....
Considering the code you've posted, the process would be executed until it reaches the compiler. The compiler would traverse the code, notice the definition of type1, type2, foo(type1 x), and bar<T>().
struct type1 {};
struct type2 {};
When it'd reached the main, it would find the call for bar<type1>();, and would call foo(type1()), which is already known, and can be used properly.
void foo(type1 x) {
std::cout << "foo(type1)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main() {
bar<type1>();
bar<type2>();
return 0;
}
Once it'd reached the next call, bar<type2>();, it would try to call foo(type2()), but no such definition would be available for usage, so it would relate this call as an unknown symbol, that must be replaced by a definition in the later processes.
After the compiler runs through the main, it reaches a new definition, that is exactly the one lacking definition on the "translation table" being created.
void foo(type2 x) {
std::cout << "foo(type2)" << std::endl;
}
So, in the next step, the compilation is able to replace the symbol with its respective definition, and the program compiles correctly.
Regards!
The answer is found via argument-dependent name lookup (ADL) (which is also mentioned in the linked question). foo(T()); has two lookups. First at template definition time, any functions defined at the point of definition are included in the overload set. This means when the compiler sees foo(T()); inside of bar, it adds only void foo(type1 x) to the overload set. However there is a second lookup that is performed, called ADL. At template instantiation time, i.e. bar<type2>(); it looks for a foo in the same namespace as the argument which is provided, which in this case is type2. Since type2 is in the global namespace, it looks for a foo that takes a type2 in the global namespace and finds it, and resolves the call. If you are looking for info from the standard, see 14.6.4.2 Candidate functions.
Try the following and watch the code fail. This is because it cannot find foo in the same namespace as a::type1.
#include <iostream>
namespace a
{
struct type1 {};
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<a::type1>();
return 0;
}
void foo(a::type1 x)
{
std::cout << "foo(a::type1)" << std::endl;
}