Why const reference discards in implicit template instantiate? - c++

I write a class with template method and use it like below.
#include<string>
using namespace std;
class A {
public:
template<typename T> void DoSomething(uint32_t index, T arg);
};
template<>
void A::DoSomething(uint32_t index,const string &arg) {
}
void Run(A &a, const string &str) {
a.DoSomething(0, str);
a.DoSomething<const string &>(0, str);
}
int main() {
A a;
Run(a, "HelloWorld");
return 0;
}
This code failed with linker error : undefined reference to `void A::DoSomething<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >(unsigned int, std::__cxx11::basic_string<char, std::char_traits, std::allocator >)
So compiler discards the const reference qualifiers.
Why this happens ? How can fix it ?

The problem is that the second parameter arg in DoSomething expects an argument to be passed by value. This means that T is deduced to be std::string and hence the general version of the function template is selected. But since there is no definition for the general version, you get the mentioned linker error.
For example,
template<typename T>
//--------vvvvv----------->by value
void func(T arg)
{
}
int main()
{
const std::string str = "name";
func(str); //T is std::string
}

It's seems the correct answer to this question is perfect forwarding mixed with type traits.
below code shows how PerfectForwardDoSomething method call correct method.
#include<string>
#include <vector>
#include <type_traits>
using namespace std;
class DataClass {
public:
string content;
bool isPersist;
DataClass(string content, bool isPersist) : content(std::move(content)), isPersist(isPersist) {}
};
class A {
private:
vector<DataClass> keepUntilDestroy;
public:
template<typename T>
void DoSomething(uint32_t index, T arg);
template<typename T>
void PerfectForwardDoSomething(uint32_t index, T &&arg) {
if constexpr (is_reference_v<T>) {
DoSomething<const typename decay<T>::type &>(index, std::forward<T>(arg));
} else {
DoSomething<T>(index, std::forward<T>(arg));
}
}
};
template<>
void A::DoSomething(uint32_t index, const DataClass &arg) {
}
template<>
void A::DoSomething(uint32_t index, DataClass arg) {
keepUntilDestroy.push_back(arg);
}
void RunRef(A &a, const DataClass &data) {
a.PerfectForwardDoSomething(0, data);
}
void RunVal(A &a, DataClass data) {
a.PerfectForwardDoSomething(0, data);
}
int main() {
A a;
RunVal(a, {"HelloWorld", false});
RunRef(a, {"HelloWorld2", true});
return 0;
}

Related

How can I build a function concept with a particular signature?

I'm writing some generic software using concepts and I want to check if a particular function symbol name exists with a signature of (void)(int,int) on a struct. To do this I've I'm thinking of approaching this problem through template specialization but I'm sort of lost.
What I want is something to work and through compile time errors if the concept is not satisfied like so:
struct TypeA {
// Passes concept
void process (int a ,int b) const {};
};
struct TypeB {
// Does not pass concept
void process (float a) const {};
};
struct TestConcepts {
/* concept code here */
TestConcepts(T t) {
process_concept(t.process);
};
};
int main(void) {
// Should pass
TestConcept(TypeA{});
// Should throw error
TestConcept(TypeB{});
return 0;
}
I'm having a hard time filling in the blanks but this is what I have so far:
struct TestConcepts {
/* concept code here */
struct process_concept {
process_concept((V*)(IA,IB)){
if (is_integral<IA>::value && is_integral<IB>::value && is_same<V, void>) {
return;
}
static_assert(false, "You must provide function called process of type (void)(int,int)");
};
};
TestConcepts(T t) {
process_concept(&t.process);
};
};
Unfortunately this doesn't work. How can I get this function signature correct?
How about using a function that returns a declared function pointer?
struct TypeA {
// Passes concept
void process (int a ,int b) const {};
};
struct TypeB {
// Does not pass concept
void process (float a) const {};
};
template<typename T>
auto TestConcepts(T) -> void(T::*)(int, int) const
{
return &T::process;
}
int main(void) {
// Should pass
TestConcepts(TypeA{});
// Should throw error
TestConcepts(TypeB{});
return 0;
}
Output:
Error(s):
source_file.cpp: In instantiation of ‘void (T::* TestConcepts(T))(int, int) const [with T = TypeB]’:
source_file.cpp:26:23: required from here
source_file.cpp:19:16: error: cannot convert ‘void (TypeB::*)(float) const’ to ‘void (TypeB::*)(int, int) const’ in return
return &T::process;
^
EDIT: more options
If you want to include void process(long int a, long int b) const; or void process(int a, int b, int c=0) const;, like aschepler is suggesting, you can use type traits.
struct TypeA {
// Passes concept
void process(int a, int b) const {};
};
struct TypeB {
// Does not pass concept
void process(float a) const {};
};
struct TypeC {
// Passes concept
void process(long int a, long int b) const {};
};
struct TypeD {
// Passes concept
void process(int a, int b, int c = 0) const {};
};
struct TypeE {
// Does not pass concept
void process(int a, int b, int c) const {};
};
#include <type_traits>
template<typename T, typename A1, typename A2, typename... An>
typename std::enable_if<
std::is_integral<A1>::value &&
std::is_integral<A2>::value
>::type
TestProcess(const T& t, void(T::*)(A1, A2, An...) const) {
t.process(1, 2);
};
template<typename T>
void TestConcepts(const T& t)
{
TestProcess(t, &T::process);
}
int main(void) {
// Passes
TestConcepts(TypeA{});
// Throws compilation error
TestConcepts(TypeB{});
// Passes
TestConcepts(TypeC{});
// Passes
TestConcepts(TypeD{});
// Throws compilation error
TestConcepts(TypeE{});
return 0;
}

Type erasure and a kind of template method pattern

Consider the following, minimal example:
struct S {
using func_t = void(*)(void *);
template<typename T>
static void proto(void *ptr) {
static_cast<T*>(ptr)->f();
}
func_t func;
void *ptr;
};
struct T {
void f() {}
};
void g(S &s) {
s.func(s.ptr);
}
int main() {
T t;
S s;
s.func = &S::proto<T>;
s.ptr = &t;
g(s);
}
The pretty obvious idea is to erase the type of a bunch of objects (like T, that is not the only available type) to create an array of instances of S, then iterate over that array and invoke a predetermined member function.
So far so good, it's easy to implement and it works.
Now I would like to provide an external function to be invoked on the erased object, something that would be like this:
template<typename T, typename F>
static void proto(void *ptr, F &&f) {
auto *t = static_cast<T*>(ptr);
std::forward<F>(f)(*t);
t->f();
}
Or this:
template<typename T>
static void proto(void *ptr, void(*f)(T &)) {
auto *t = static_cast<T*>(ptr);
f(*t);
t->f();
}
To be invoked as:
s.func(s.ptr, [](auto obj){ /* ... */ });
A kind of template method pattern where the extra functionalities are provided by the caller instead of a derived class.
Unfortunately I cannot do that for I cannot reduce the specializations to something homogeneous to be assigned to a function pointer.
The only alternative I can see is to define a custom class like the following one:
struct C {
template<typename T>
void f(T &t) { /* ... */ }
// ...
};
Where f dispatches somehow the call internally to the right member function, then use it as:
struct S {
using func_t = void(*)(void *, C &);
template<typename T>
static void proto(void *ptr, C &c) {
auto t = static_cast<T*>(ptr);
c.f(*t);
t->f();
}
func_t func;
void *ptr;
};
That is not far from what I would do by using a lambda, but it's more verbose and requires me to explicitly declare the class C.
Is there any other valid alternative to achieve the same or is this the only viable solution?
Assuming you can enumerate the types you wish to support you can do this:
#include <iostream>
#include <string>
#include <vector>
template <class... Ts>
struct PseudoFunction {
private:
template <class T>
static void (*function)(T &);
template <class T>
static void call_func(void *object) {
return function<T>(*static_cast<T *>(object));
}
template <class Fun>
static void assign(Fun) {}
template <class Fun, class Head, class... Tail>
static void assign(Fun fun) {
function<Head> = fun;
assign<Fun, Tail...>(fun);
}
public:
template <class T>
PseudoFunction(T *t)
: object(t)
, func(call_func<T>) {}
template <class F>
static void set_function(F f) {
assign<F, Ts...>(f);
}
void operator()() {
func(object);
}
private:
void *object;
void (*func)(void *);
};
template <class... Ts>
template <class T>
void (*PseudoFunction<Ts...>::function)(T &) = nullptr;
//example types that are not related and not copy constructible
//but have the same member function name and signature
struct T1 {
T1() = default;
T1(const T1 &) = delete;
void func(double d) {
std::cout << "T1: " + std::to_string(d) + '\n';
}
};
struct T2 {
T2() = default;
T2(const T2 &) = delete;
void func(double d) {
std::cout << "T2: " + std::to_string(d) + '\n';
}
};
int main() {
T1 t1;
T2 t2;
using PF = PseudoFunction<T1, T2>;
std::vector<PF> funcs;
funcs.push_back(&t1);
funcs.push_back(&t2);
PF::set_function([](auto &object) { object.func(3.14); });
for (auto &f : funcs) {
f();
}
}
(demo)
It has decent call syntax (just that you have to specify the function before calling the objects) and some overhead of setting potentially unused function pointers.
One could probably make a wrapper that does the set_function and iterating over the PFs in one go.

Function template specialization type - is it optional?

Is the <const char*> optional in below code? I found that g++ and clang compiles without it just fine.
template<typename T>
void debugRep2(T const& t) {
std::cout << "debugRep(const T& t)\n";
}
template<>
void debugRep2<const char*>(const char* const& t) {
//^^^^^^^^^^^^^
std::cout << "const char*& t\n";
}
int main() {
int n;
int *pn = &n;
debugRep2(n);
debugRep2(pn);
}
The templated type is already specified at the function parameter and can be deduced by the compiler
template<>
void debugRep2<const char*>(const char* const& t) {
// ^^^^^^^^^^^ already present
// ...
}
So yes, in this case it is optional.
In fact the common way to write that specialization would be
template<>
void debugRep2(const char* const& t) {
// ...
}

Passing in a function which increments elements of boost::fusion:vector

I found the following code which I am using as a basis. It describes how to populate a boost::fusion::vector with the values 6:
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container.hpp>
struct F {
F(int blah): blah(blah){}
template <typename T>
void operator()(T& t) const {
t = blah;
}
int blah;
};
template <typename T>
void apply_for_each_to_assign(T &t)
{
boost::fusion::for_each(t, F(6));
}
int main() {
boost::fusion::vector<int, double, int> idi;
apply_for_each_to_assign(idi);
}
My question is this, instead of populating every element with the value 6- what would be the neatest way to have every element incrementing by one? So
v[0] = 1
v[1] = 2
etc? I presume I would need to write an increment function but I am not sure how I need to incorporate it in to the above code?
You can use fold.
fold takes a function A f(A, B) where B is your element type, and a intial A value and call it on all the elements. It is rougly equivalent to f(f(f(initial, first_elem), second_elem), third_elem).
You should declare the functor like this:
struct accumulator
{
typedef int result_type;
template<typename T>
int operator()(int value, T& t) const
{
t += value;
return value + 1;
}
};
And here's the usage:
template <typename T>
void apply_for_each_to_assign(T &t)
{
boost::fusion::fold(t, 1, accumulator());
}
Here a whole example with printing:
#include <boost/fusion/algorithm/iteration/fold.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/include/fold.hpp>
#include <boost/fusion/container.hpp>
#include <iostream>
struct accumulator
{
typedef int result_type;
template<typename T>
int operator()(int value, T& t) const
{
t += value;
return value + 1;
}
};
struct Print {
template <typename T>
void operator()(T& t) const {
std::cout << t << std::endl;
}
};
template <typename T>
void apply_for_each_to_assign(T &t)
{
boost::fusion::fold(t, 1, accumulator());
boost::fusion::for_each(t, Print());
}
int main()
{
boost::fusion::vector<int, double, int> idi;
apply_for_each_to_assign(idi);
}

C++. How to define template parameter of type T for class A when class T needs a type A template parameter?

Executor class has template of type P and it takes a P object in constructor. Algo class has a template E and also has a static variable of type E. Processor class has template T and a collection of Ts.
Question how can I define Executor< Processor<Algo> > and Algo<Executor> ? Is this possible? I see no way to defining this, its kind of an "infinite recursive template argument"
See code.
template <class T>
class Processor {
map<string,T> ts;
void Process(string str, int i)
{
ts[str].Do(i);
}
}
template <class P>
class Executor {
P &p;
Executor(P &inp) : p(inp) {}
void Bar(string str, int i) {
p.Process(str,i);
}
Execute(string str)
{
}
}
template <class E>
class Algo
{
static E e;
void Do(int i) {}
void Foo()
{
e.Execute("xxx");
}
}
main ()
{
typedef Processor<Algo> PALGO; // invalid
typedef Executor<PALGO> EPALGO;
typedef Algo<EPALGO> AEPALGO;
Executor<PALGO> executor(PALGO());
AEPALGO::E = executor;
}
EDIT ****************************
A little clarification. Executor is a singleton that provides a service. All Algo objects need the services of Executor. Executor will sometimes generate reports that need to be sent to a specific Algo object. They get sent to the correct Algo through Processor.
Basic issue is that Algo is needed to define Executor and Executor is needed to define Algo.
Tried reproducing your code, not quite sure what you are trying to achieve. For starters, this is what I modified it to:
#include <string> //Added
#include <map> //Added
using namespace std;//Added
template <class T>
class Processor {
map<string,T> ts;
void Process(string str, int i) {
ts[str].Do(i);
}
};
template <class P>
class Executor {
Processor<P> &p; //Was Proc ???
Executor(P &p) : Processor<P>(p) {} //Was Proc ???
void Foo(string str, int i) {
p.Process(str,i);
}
void Execute(string str){} //Added return type void
};
template <class E>
class Algo {
public: //Added
static E e;
void Do(int i) {}
};
main () {
typedef Processor< Algo<int> > PALGO; //Added template argument to Algo
typedef Executor<PALGO> EPALGO;
typedef Algo<EPALGO> AEPALGO;
Executor<PALGO> executor(PALGO());
AEPALGO::e = executor;
}
Modified Proc to Processor in Executor definition - (what is Proc?) and gave it template argument, in the typedef Processor> PALGO;
Then AEPAGO::E --> thats a template param, not class Algo member - so AEPAGO::e.
Now you will get an error that can be more manageable. It needs a copy constructor to convert types.
You can use inheritance.
class X : public Executor<Processor<Algo<X>>> {};
Else, this is not possible.
AFAICS, you cannot do that with the same Executor type. Otherwise you would have to define
Executor<Processor<Algo<Executor<Processor<Algo<...> > > > > >
It might work, if you define it with some other type, provided that makes any sense technically
class X {
...
};
Executor<Processor<Algo<Executor<Processor<Algo<X> > > > > >
or with typedef
class X {...};
typedef Processor<Algo<X> > PALGO;
typedef Executor<PALGO> EPALGO;
typedef Algo<EPALGO> AEPALGO;
Executor<PALGO> executor(PALGO());
Since Executor is a singleton, you can move its definition out of Algo either in it's own singleton class or in Executor. Then make all the Algo function that need to know about Executor template member functions.
template <class P>
class Executor {
static Executor e;
P &p;
Executor(P &p) : Proc(p) {}
void Bar(string str, int i) {
p.Process(str,i);
}
Execute(string str)
{
}
public:
static Executor& getE(){ return e;}
}
class Algo
{
void Do(int i) {}
template <class E>
void Foo()
{
E::getE().Execute("xxx");
}
}
Solved! see comments. //****
#include <string>
#include <map>
#include <iostream>
using namespace std;
template <class T>
class Processor {
public:
map<string,T*> ts;
void Process(string str, int i)
{
ts[str]->Do(i);
}
};
template <class P>
class Executor {
public:
P &p;
Executor(P &inp) : p(inp) {}
void Bar(string str, int i) {
p.Process(str,i);
}
void Execute(string str)
{
cout << " Executor::Execute " << str << endl;
}
};
template <template <class> class E> //**********
class Algo
{
string str;
public:
Algo(const string &s) : str(s) {}
static E<Processor<Algo>> *e; //**********
void Do(int i) { cout << str << "::Do(" << i <<")"<< endl; }
void Foo()
{
e->Execute(str);
}
};
template <template <class> class E>
E< Processor<Algo<E> > >* Algo<E>::e; //**********
int main(int argc, char **argv)
{
typedef Algo<Executor> EALGO;
typedef Processor<EALGO> PALGO;
typedef Executor<PALGO> EPALGO;
PALGO p;
EPALGO executor(p);
EALGO::e = &executor; //**********
EALGO ealgo1("algo1"), ealgo2("algo2");
p.ts["algo1"] = &ealgo1;
p.ts["algo2"] = &ealgo2;
ealgo1.Foo();
ealgo2.Foo();
executor.Bar("algo1",1111);
executor.Bar("algo2",2222);
}