Overload for undefined type - c++

I am trying to do some overload on the template function, following are the examples
do_something.h
template<typename T>
void do_something(T const &input){/*....*/}
void do_something(std::string const &input);
void do_something(boost::container::string const &input);
so far, so good, but what if I want to overload a non-defined type?
like using a type some_type have not defined in the header file
void do_something(some_type const &input);
I want to use it like this
main.cpp
#include "do_something.h"
#include "some_type.h"
#include <boost/container/string.hpp>
int main()
{
do_something(std::string("whatever"));
do_something(boost::container::string("whatever"));
//oops, some_type() never defined in the header file, this
//function will call the template version, but this is not
//the behavior user expected
do_something(some_type());
}
Since some_type is not a POD, not a std::string, boost::container::string.I guess I could designed a traits to do some compile time checking
template<typename T>
typename boost::enable_if<is_some_type<T>::value, T>::type
do_something(T const &input){//.....}
But do I have a better way to do it?
I need compile time type checking, so I use template.All of the types calling this function will do similar jobs based on different types, so I prefer overload.I do not need to save the state, so I prefer function rather than class.
Hope this could help you know more about what I intent to do.Thank you

but what if I want to overload a non-defined type?
You need to provide the declaration of
void do_something(some_type const &input);
before you call do_something with an object of type some_type. Otherwise, the template version will be used.
#include "do_something.h"
#include "some_type.h"
// This is all you need. You can implement the function here
// or any other place of your choice.
void do_something(some_type const &input);
#include <boost/container/string.hpp>
int main()
{
do_something(std::string("whatever"));
do_something(boost::container::string("whatever"));
//oops, some_type() never defined in the header file, this
//function will call the template version, but this is not
//the behavior user expected
do_something(some_type());
}

Related

C++ template not recognizing data types

I have the following simplified code where the compiler is not recognizing the data types and I am not sure why. In the code, I want to be able to pass a map, where the keywords can either be a std::string, a char, or an int. I also want the user to be able to choose whether the associated value is a float or double. In addition, based on the type of the associated value I want the return to either be std::vector<float> or std::vector<double>. Due to the variability in data types, I choose to code this problem as a template.
// main.cpp
#include "test.hpp"
#include <iostream>
#include <math.h>
#include <map>
#include <tuple>
double func6(std::map<char, double> arr);
int main(int argc, const char * argv[]) {
std::map<char, double> inputs;
inputs['x'] = 2.0;
inputs['y'] = 5.438;
std::tuple<std::vector<double>, std::vector<double>> answer;
ODESolver q;
answer = q.ode_solver(inputs, func6);
// - The line below this was tried and it did not work
// any better than the line of code above this.
// answer = q.ode_solver<char, double>(inputs, func6);
return 0;
}
double func6(std::map<char, double> arr)
{
return arr['y'] * log(arr['y']) / arr['x'];
}
The .hpp file has the following information.
#ifndef test_hpp
#define test_hpp
#include <stdio.h>
#include <tuple>
#include <vector>
#include <map>
#include <functional>
class ODESolver
{
public:
template<class char_type, class real_type>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const std::function<real_type(std::map<char_type, real_type>)>& func)
{
// - This function does not work with the function call
// as written
// - The code in this function is irrelevant, it was just
// created to have returnable information of the correct
// type to test the function call
std::vector<real_type> one = {0.0, 1.0};
std::vector<real_type> two = {0.0, 1.0};
std::tuple<std::vector<real_type>, std::vector<real_type>> three(one, two);
return three;
}
};
#endif /* test_hpp */
The compiler does not allow the template shown above, because it does not recognize a matching function call for answer= q.ode_solver(inputs, func6) in the main program. However, if I replace the std::function statement with the following code it works fine.
template<class char_type, class real_type>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const std::function<double(std::map<char, double>)>& func)
All I am doing is replacing the templated parameters with the parameters I want to use in this exact situation, but that defeats the reason for using a template. I have also tried calling the function with answer = q.ode_solver<char, double>(inputs, func6); and it still does not recognize the function. What am I missing?
Implicit conversions (from the function pointer to std::function in this case) won't be considered in template argument deduction.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
You can add an explicit conversion, e.g.
answer = q.ode_solver(inputs, static_cast<std::function<double(std::map<char, double>)>>(func6));
or specify the template arguments explicitly (I'm not sure why you said it didn't work, see the live demo linked below)
answer = q.ode_solver<char, double>(inputs, func6);
LIVE
Or just add another template parameter instead of using std::function.
template<class char_type, class real_type, class F>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const F& func)

extern declared template specialized function not found

i'm trying to implement a clone of the json serialization library nlohmann::json as a learning experience, and i'm having trouble with the interface for user defined (json<->User type) conversion.
Basically i want the user to be able to overload two function: to_json(json&, const Type&) and from_json(const json&, Type&). Then the library will use overload resolution to call theses function in the templated operator= and one argument constructor.
It works fine when i'm just defining theses function directly but when i try to make a template definition for multiple types (in this example the class S) the linker can't find the definition.
I've tried to explicitly instantiate the function for individual instances of the templated class although i would prefer avoiding having to do that in the final product.
I'm guessing it has to do with the fact that templated function don't have the same signature than free function, but i don't see what i can do to make it work. What am i missing ? I also couldn't find result on google so is it a documented pattern or an anti pattern ?
Thanks you. Below i tried to minimize my problem in one short example.
Class.hpp
#pragma once
#include <cstdio>
template<size_t i>
class S {
size_t n = i;
};
template<size_t i>
void g(const S<i>& s) {
printf("S<%u>\n", i);
}
Class.cpp
#include "Class.hpp"
template void g<10>(const S<10>&); // <-- Even with explicitly instanciation
void g(const bool& b) {
printf("%s\n", b ? "true" : "false");
}
main.cpp
#include "Class.hpp"
template<typename T>
void f(T t) {
extern void g(const T&);
g(t);
}
int main(int, char**) {
S<10> s;
//f(s); <-- linker error: void g(class S<10> const &) not found.
f(false);
}
The name lookup for g in g(t) call stops as soon as it finds extern void g(const T&); declaration; it never sees the declaration of the function template. So the compiler generates a call to a regular non-template function named g taking const S<10>&. But no such function is defined in your program - hence linker error.

Use arbitrary functions as template parameter arguments

I have an Apache module (.so) that contains a class I'm trying to completely decouple from Apache itself. The biggest source of frustration is the debug logging. I want to be able to pass the logging function to the class through the template parameters. I can get the proof of concept to work fine when everything is in the same translation unit, but it falls over once they're not because the logging function is an 'undefined reference':
/tmp/ccPdPX2A.o: In function `main':
test.cpp:(.text+0x81): undefined reference to `void C::DoThis<&(LogIt(char const*, ...))>()'
collect2: ld returned 1 exit status
This also happens when Apache tries to load the module containing the class.
The code below reproduces the problem:
// main.cpp
#include <iostream>
#include "C.h"
void LogIt(const char*, ...)
{
std::cout << "GADZOOKS!\n";
}
int main(int argc, char* argv[])
{
C c;
c.DoThis<LogIt>();
}
// C.h
typedef void (*LogFunction)(const char*, ...);
class C
{
public:
template <LogFunction L>
void DoThis();
template <LogFunction L>
void DoThat();
};
// C.cpp
#include "C.h"
template <LogFunction L>
void C::DoThis()
{
L("DoThis!");
DoThat<L>();
}
template <LogFunction L>
void C::DoThat()
{
L("DoThat!");
}
I'd prefer not to have to resort to having the function passed as a function parameter, i.e.
template <typename F>
void C::DoThis(F f)
{
f("DoThis!");
}
because I'd like to structure the code in such a way that the compiler is able to figure out if the body of LogIt is empty (which it will be for Release builds) and not generate any code for the call, and I'd have to pass it as an argument everywhere in the class.
Can it be done?
Okay I recreated everything,
This error undefined reference to void C::DoThis<&(LogIt(char const*, ...))>() is explained here
Now if you do #include "C.cpp" referring above, this will lead to
undefined reference to void C::DoThat<&(LogIt(char const*, ...))>()
So fix:
template <LogFunction L>
void C::DoThat() //Notice :: used here
{
L("DoThat!");
}
and everything complies and execute !
This is because you have your templates invisible at the point where compiler is supposed to instantiate them as you only have a declaration in C.h and a definition in C.c.
Either move template definitions to header or force instantiation in C.c. You will have to provide LogIt declaration in C.c for that.
You need to put template definition in the same as the place where its declared. So that means you need to put your LogIt function where it was declared in the header file. As of right now, we are not able to explicitly separate template declaration and its definition like that.

C++ access to members of an inherited class, where the inherited class is a template parameter

I am working with the libMesh FEM library and am trying to develop a class (EqCore) that inherits from libMesh. This class will provide some additional features that are inherited again by a class that I want to actually use (MainEq).
The two functions, set_constant and get_constant, are causing the error below. These worked as shown with a different inheritance scheme (see Inheritance of template class with a template member function in C++). The difference with this problem is that now the template parameter (Type) is actually a class that gets inherited. Is this a dangerous practice?
I would appreciate any help getting this code working or finding an alternate method.
ERROR MESSAGES:
In member function ‘void EqCore::set_constant(std::string, ParamType)’:
test_libmesh.cpp:26:57: error: expected primary-expression before ‘>’ token
In member function ‘ParamType EqCore::get_constant(std::string)’:
/home/slaughter/Documents/programs/source/test_libmesh.cpp:31:76: error: expected primary-expression before ‘>’ token
PROGRAM:
//! \example test_libmesh.cpp
#include <string>
using std::string;
// libMesh includes
#include <libmesh.h>
#include <libmesh_common.h>
#include <equation_systems.h>
#include <transient_system.h>
#include <explicit_system.h>
#include <parameters.h>
#include <mesh.h>
using namespace libMesh;
// Fundamental behavior that will be used among many classes
template <typename Type> class EqCore : Type{
public:
// Class constructor
EqCore(EquationSystems& sys, string name) : Type(sys, name, 1){}
// A function for storing a constant value (causes error)
template<typename ParamType> void set_constant(std::string name, ParamType var){
Type::get_equation_systems().parameters.set<ParamType>(name) = var;
}
// A function for retrieving a constant value (causes error)
template<typename ParamType> ParamType get_constant(std::string name){
ParamType output = Type::get_equation_systems().parameters.get<ParamType>(name);
return output;
}
};
// A test class derived
class MainEq : public EqCore<ExplicitSystem>{
public:
// Constructor
MainEq(EquationSystems& sys) : EqCore(sys, "main"){ }
};
// Begin main function
int main (int argc, char** argv){
// Initialize libMesh and create an empty mesh
LibMeshInit init (argc, argv);
Mesh mesh;
// Test w/o any of the above classes
EquationSystems eq_sys(mesh);
eq_sys.parameters.set<double>("test1") = 1;
printf("Test 1: %f\n", eq_sys.parameters.get<double>("test1"));
// Test my class set/get functions
MainEq eq(eq_sys);
eq.set_constant<double>("test2", 2);
printf("Test 2: %f\n", eq.get_constant<double>("test2"));
}
Because you are inside a template, the compiler cannot determine that set is a template automatically during parse time, and it's assuming that set is a non-template, and hence the parse fails.
The solution is to explicitly inform the compiler that set is a member template, as such.
Type::get_equation_systems().parameters.template set<ParamType>(name) = var
In C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond, by David Abrahams, Aleksey Gurtovoy (Amazon) it is explained as follows:
double const pi = 3.14159265359;
template <class T>
int f(T& x)
{
return x.convert<3>(pi);
}
T::convert might be a member function template, in which case the
highlighted code passes pi to a specialization of convert<3>. It
could also turn out to be a data member, in which case f returns
(x.convert < 3 ) > pi. That isn't a very useful calculation, but the
compiler doesn't know it.
The template keyword tells the compiler that a dependent name is a
member template:
template <class T>
int f(T& x)
{
return x.template convert<3>(pi);
}
If we omit template, the compiler assumes that x.convert does not
name a template, and the < that follows it is parsed as the less-than
operator.

failing to invoke template class, c++

I've defined a template class like so (providing .hpp file):
#ifndef PERSOANLVEC_H_
#define PERSOANLVEC_H_
#include <vector>
using namespace std;
template<class T, class PrnT> class PersoanlVec {
public:
PersoanlVec();
~PersoanlVec();
void push_back(T t);
void erase(int index);
PersoanlVec& operator[](int index);
const PersoanlVec& operator[](int index) const;
void print() const;
size_t size();
private:
vector<T> _vector;
};
#endif /* PERSOANLVEC_H_ */
Now, everything compiles ok with this class. When I try to use it I get
undefined reference to PersoanlVec<Person, Person>::PersoanlVec()'.
Here's where I call it:
#include "Person.h"
#include "PersoanlVec.hpp"
#include <cstdlib>
int main(void)
{
Person p1("yotam");
Person p2("yaara");
PersoanlVec<Person,Person> *a = new PersoanlVec<Person,Person>(); //<---ERROR HERE
return EXIT_SUCCESS;
}
This is my first try with templates, its not very clear for me obviously. I DO have a constructor with no parameters, Any ideas?
Thanks!
Do you have the content of your constructor and functions in a .cpp file? If yes, there's your problem. Put them in the header file, possible just inline in the class itself:
template<class T, class PrnT> class PersoanlVec {
public:
PersoanlVec(){
// code here...
}
~PersoanlVec(){
// code here...
}
void push_back(T t){
// code here...
}
void erase(int index){
// code here...
}
PersoanlVec& operator[](int index){
// code here...
}
const PersoanlVec& operator[](int index) const{
// code here...
}
void print() const{
// code here...
}
size_t size(){
// code here...
}
private:
vector<T> _vector;
};
For the reason, have a look here.
I am pretty sure you just forgot to add the file to the compilation process. Be careful with your misspelling, since that can cause generic pain.
Whenever you have different compilation units (classes for example, each with their .h/.cpp), your classes need to know of the interfaces, reason for which you normally include the header files, yet the compiler also needs to know the implementations so that it can bind together your binary file.
As such, you will need to call the compiler passing all the .cpp files in your project to it, otherwise it will fail letting you know you are referencing unimplemented pieces.
You need to have all of your template function definitions held in the header file rather than the CPP file - this is basically because the template definition will be used multiple times to create multiple types depending on what parameters you pass in to it as type parameters around your code. The only template related functions that should ever be defined in the CPP file are template specialization functions - those where you want to explicitly say (if user passed in type A and B then do this specifically instead of the default action).