Template member function pointer to non-template member function pointer - c++

I have a class with a template method and would like to store its specializations in a container. My question is whether it's valid to cast the specialized template method pointer to a non-template method pointer of the same class that shares the same signature. Consider:
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
struct S {
using Method = void(S::*)();
template <typename T>
void method1() {
cout << "method1(): " << T() << endl;
}
template <typename T, typename U>
void method2() {
cout << "method2(): " << T() << ", " << U() << endl;
}
void call(string name)
{
auto method_pair = methods.find(name);
if (method_pair == methods.end()) {
cout << name << " not found" << endl;
return;
}
Method& method = method_pair->second;
(this->*method)();
}
unordered_map<string, Method> methods;
};
int main()
{
S s;
s.methods["method_int"] = &S::method1<int>;
s.methods["method_bool"] = &S::method1<bool>;
s.methods["method_int_int"] = &S::method2<int, int>;
s.methods["method_bool_int"] = &S::method2<bool, int>;
cout << boolalpha;
s.call("method_int");
s.call("method_bool");
s.call("method_int_int");
s.call("method_bool_int");
s.call("nonexistant");
return 0;
}
Output:
method1(): 0
method1(): false
method2(): 0, 0
method2(): false, 0
nonexistant not found
The above code compiles and runs just fine with no warnings on my setup. I'm pretty new to C++ member function pointers and I've read that casting them can be dangerous so that's why I'm asking.
Thanks in advance.

After you instantiate a template method with distinct types it gets all the properties of a regular method: it becomes a distinct function with an address, name (that includes the types you used for instantiation), etc. So your approach is valid.

Related

Using std::bind on template class member

Consider the code below
#include <iostream>
#include <functional>
class Solver{
public:
int i = 0;
void print(){
std::cout << "i solved" << std::endl;
}
};
template <typename T> class ThingHandler{
public:
template <typename B,typename C>
void handleThing(T& solver,B paramOne,C paramTwo){
std::cout << "i handled something " << std::endl;
solver.print();
std::cout << paramOne << paramTwo;
}
};
class CantHandle{
public:
void needHelp(std::function<void(int,int)> handleThing){
int neededInt = 0;
int neededIntTwo = 2;
handleThing(neededInt,neededInt);
}
};
int main() {
ThingHandler<Solver> thingHandler;
CantHandle cantHandle;
Solver solver;
solver.i = 10;
auto fp = std::bind(&ThingHandler<Solver>::handleThing<Solver,int,int>,
thingHandler,solver,std::placeholders::_1,std::placeholders::_1);
//the row above is what I want to achieve
cantHandle.needHelp(fp);
return 0;
}
I'm getting the following error:
140: error: no matching function for call to ‘bind(, ThingHandler&, Solver&, const
std::_Placeholder<1>&, const std::_Placeholder<1>&)’ 37 | auto
fp = std::bind(&ThingHandler::handleThing,
thingHandler,solver,std::placeholders::_1,std::placeholders::_1);
What I want to do is have a generic class that solves some problem. Then call upon a specialization of that class. So in the case above I want ThingHandler to be (Solver& solver, int paramOne, int paramTwo). I'm not quite sure how to achieve this.
Member function you bind takes two template type parameters, so Solver is redundant in template argument list.
Should be:
&ThingHandler<Solver>::handleThing<int,int>
Some remarks: your code binds handleThing for a copy of thingHandler instance.
Also first bound parameter - solver, is copied into functor generated by bind.
If you want to avoid these two copies, use & or std::ref:
auto fp = std::bind(&ThingHandler<Solver>::handleThing<int,int>,
&thingHandler,std::ref(solver),std::placeholders::_1,std::placeholders::_2);

how to return a reference to a default value of a non-type template argument

I have done a lot of research on this but I wasn't able to find a design pattern addressing the problem. This is a minimal description of what I'm trying to perform.
#include <iostream>
using namespace std;
template <class T, T default_value=T{}>
class A{
private:
T inclassValue;
public:
A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_value;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
/*
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
*/
return 0;
}
The code will compile, link and output as expected
a[0]=0
a[1]=4
The compiler complains though and issues a warning for the line of code where default_value is used
return default_value;//Returning reference to local temporary object
which makes some sense. Uncommenting the last part in main and compiling, the compiler issue this time an error while building the template
template <class T, const T default_value= T{}>//A non-type template parameter cannot have type 'two_int'
while what I ideally hope for is
b[0]=0,0
b[1]=3,5
I was able to come up with a solution by adding an extra helper class, that will provide the default_value of T (as a static member), to the template arguments. I'm not convinced by the robustness of my trick and I was wondering if there exists a design pattern addressing this. The warning for types and the error for non-types. Also, I shall add that my primary goal is to be able to provide default_value at will (6 for int for example instead of 0).
Thanks
Not exactly sure what you're looking for, but perhaps a static helper finishing for creating a static default T could be useful:
template <typename T>
static const T& default_value() {
static const T* t = new T{};
return *t;
}
Note this will construct T at most once even across threads (in c++11), but still never destruct T. Since it's static, it's likely the lack of destruction is acceptable, but this of course depends on T.
Here is one version that forwards arguments to the constructor of a default_value stored as constexpr. You are quite limited here as to what is valid to pass as arguments (not sure exactly how limited) so it will depend on your use-case.
#include <iostream>
using namespace std;
template <class T, auto... Args>
class A{
private:
T inclassValue;
constexpr static T default_val = T{Args...}; // Changed to curly brackets here
public:
constexpr A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_val;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
return 0;
}

GCC shared_ptr and make_shared on map separated var type error

I want to use std::shared_ptr and std::make_shared and create a map list with separated variable types ... My compiler is GCC and this is my source
#include <iostream>
#include <cstring>
#include <memory>
#include <string>
#include <map>
using namespace std;
class key_base {
public:
virtual ~key_base() = default;
key_base() = default;
template <typename T> const T & Read();
};
template <typename T>
class key : public key_base {
private:
T storage_;
public:
key(const T & __storage) {
storage_ = __storage;
}
const T & Read() { return storage_; }
};
int main() {
map <int, std::shared_ptr <key_base>> List;
List[0] = std::make_shared <key<string>>("Hello");
List[1] = std::make_shared <key<string>>("How old are you?");
List[2] = std::make_shared <key<int>>(22);
for (auto thisItem : List) {
if(thisItem.first == 2)
cout << thisItem.first << "= (" << thisItem.second->Read<int>() << ")" << endl;
else
cout << thisItem.first << "= (" << thisItem.second->Read<string>() << ")" << endl;
}
return 0;
}
I know one thing about key_base (Read) function which need to be virtual and = 0 and also it's must be template (to get the type of var) and it's not possible in GCC (but possible in Microsoft Compiler). What should I do for this too?
Problem is that you think that dynamic polymorphism will work with templates.
Basically template declaration template <typename T> const T & Read(); in base_class is completely useless.
How do you think compiler deduce what should be done for Read() if base class is used? There is no definition of this template and compiler has no idea how to reach subclasses where you are defining this methods.
Your design is wrong and since this is classic XY problem we are unable to help you to resolve this properly.
Looks like you should take a look on new template from C++17:
std::any
To make it work (I hate the code design), you need add missing template definition after key class:
template <typename T>
const T & key_base::Read()
{
if (auto subClassObject = dynamic_cast<key<T> *>(this)) {
return subClassObject->Read();
}
throw domain_error { "Invalid Read use" };
}
It works for Visual Studio.
And it works for GCC.

How do I detect if a template parameter is a builtin or not?

I want to use SFINAE to stop from explicitly calling the destructor because MSVS 2010 considers it an error when done on a builtin type pointer.
How would I do this?
You might look at it from the wrong angle: You shouldn't exclude what does not work, you should detect what does work. In your case, you are trying to check if a given type T is a class and hence you could call the destructor.
That said, you want std::is_class. If it is not available for your compiler, there is Boost.TypeTraits' boost::is_class available which works with VC++ 8 and newer.
This shows how to specialize a function so it is called for fundamental data types in C++.
template < class T>
void delete_object(T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = 0) {
// Do nothing because this is not an object
}
template<class T>
void delete_object(T* object) {
delete object;
}
int main()
{
int arithmetic1 = 1;
delete_object(arithmetic1);
float arithmetic2 = 1;
delete_object(arithmetic2);
Object* object1 = new Object();
delete_object(object1);
return 0;
}
Here are the other fundamental tests
std::is_integral<> - 'char' up to 'long long'
std::is_floating_point - 'float' up to 'long double'
std::is_signed<> - signed types
std::is_unsigned<> - unsigned types
std::is_arithmetic - is_integral<> OR is_floating_point<>
std::is_fundamental<> - is_arithmetic<> OR 'void'
With the following type function we can determine whether a type is a class type:
// traits/isclasst.hpp
template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(…);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};
This template uses SFINAME principle.
The following program uses this type function to test whether certain types and objects are class types:
// traits/isclasst.cpp
#include <iostream>
#include "isclasst.hpp"
class MyClass {
};
struct MyStruct {
};
union MyUnion {
};
void myfunc()
{
}
enumE{e1}e;
// check by passing type as template argument
template <typename T>
void check()
{
if (IsClassT<T>::Yes) {
std::cout << " IsClassT " << std::endl;
}
else {
std::cout << " !IsClassT " << std::endl;
}
}
// check by passing type as function call argument
template <typename T>
void checkT (T)
{
check<T>();
}
int main()
{
std::cout << "int: ";
check<int>();
std::cout << "MyClass: ";
check<MyClass>();
std::cout << "MyStruct:";
MyStruct s;
checkT(s);
std::cout << "MyUnion: ";
check<MyUnion>();
std::cout << "enum: ";
checkT(e);
std::cout << "myfunc():";
checkT(myfunc);
}
The program has the following output:
int: !IsClassT
MyClass: IsClassT
MyStruct: IsClassT
MyUnion: IsClassT
enum: !IsClassT
myfunc(): !IsClassT

overloading template function

Currently, I encounter some difficulty in overloading a certain function. here's my code:
template<typename Value>
bool process(Value thisValue)
{
return processAccordingToTheType(thisValue);
}
So, there are two overloaded function of processAccordingToTheType:
bool processAccordingToTheType(int thisValue){}
bool processAccordingToTheType(string thisValue){}
when I try to compile it, it said:
error C2665: 'processAccordingToTheType' : none of the 2 overloads could convert all the argument types
what do I need to do?
Update:
int main()
{
int i = 1;
process <int> (i);
}
From your sample code I understand you need two things to be done:
Call a type specific process function
Restrict these calls to string and int types
Wrapping the processAccordingToType function inside process<T> is completely redundant: process<T> actually means 'process according to type'. The keyword here is 'template specialization'. You need to specialize your 'process according to type' method for int and string.
You can do this as below:
#include <iostream>
using namespace std;
template<typename T>
bool process(T t)
{
// call a Compile-Time Assertion
cout << "I don't want this to be called." << endl;
}
template <>
bool process<int>(int i)
{
cout << "process(int) called." << endl;
}
template <>
bool process<string>(string s)
{
cout << "process(string) called." << endl;
}
int main()
{
process(1);
process(string("s"));
process(1.0d);
}
Output:
process(int) called.
process(string) called.
I don't want this to be called.
Ideally, you want to prevent the users of your API calling process with other types. Allowing them to call and handling this at runtime (like it's done in my example) is not acceptable. You achieve this with Compile-Time Assertions. Read "Modern C++ Designs" by Andrei Alexandrescu for ways of doing that.
Look into template specialization. Does what you're looking for without deferring to another function based on type.
http://www.cprogramming.com/tutorial/template_specialization.html
You can overload function templates with either a non-template function or another template function. Make sure that whatever you do, you test incrementally as template errors are notoriously hard to understand.
http://www.cplusplus.com/doc/tutorial/templates/
#include <iostream>
using namespace std;
template <typename Value>
bool processAccordingToTheType( Value thisValue ){
cout << "Generic Type" << endl;
return false;
}
bool processAccordingToTheType(int thisValue){
cout << "int type" << endl;
return true;
}
template <typename Value>
bool process( Value thisValue ){
return processAccordingToTheType(thisValue);
}
int main( int argc, char* argv[] ){
cout << process( 1 ) << endl;
cout << process( "Hello" ) << endl;
return 0;
}