I've seen this bit of code which I thought was great because it saved me from re-writing getter member functions.
#define GET(n_,N_) \
template<typename T> \
const T &get##N_() const \
{ \
return n_; \
} \
From what I know, Macros "write" code at compile time, therefore injecting the function template inside each class and because it's a template, it can compensate for any type.
So I ended up with this:
class Foo
{
int m_a;
GET(m_a,A)
};
then I used like this:
std::cout<< foo->getA<int>() <<std::endl;
My question is, WHEN and WHERE should we use macro templates?
And is there a way to NOT to specify the type when you are calling the getA member function? Is this because it's in a different namespace?
I'm going to suggest that mixing macros and templates will cause you to wind up with the weak points of both, as you've observed. The template return type of a function can never be inferred so you would always have to specify it. BUT luckily there's a solution, and it involves spelling the type into your macro:
#define GETTABLE_ATTR(type, name) \
private:
type name_; \
public:
type get_##name() const \
{ \
return name_; \
}
Whether using this macro is a good idea is still subjective - remember that you only write code once, and you're best served by writing it in the way that will both prevent mistakes as you write it AND will make maintaining the code easiest.
As also speaking for c++14 there are still needs for having c macros involved.
I have two really often used macros in combination with MTP to get a a compile time constant which tells me if a method or attribute is existing in a class. This simply needs the name of the function which can not be given as parameter to a template. So I prepared that inside a c macro which "writes" my template which then can be used inside enable_if clause.
I personally dislike your idea from "automated getters", but this is only a question of taste.
As always in programming: If the thing helps, is not "undefined behaviour", is well documented in the code and could NOT be done with a more strait forward way the use of c macros is allowed. For me c macros are a kind of "self-defence" for not integrated language features.
Another popular example is enumeration with associated text for some kind of reflection or for serialisation.
The example to catch the existence of a method:
#define DECLARE_HAS_METHOD_FULL_SIGNATURE(NAME) \
template<typename, typename T>\
struct has_method_full_signature_ ## NAME {\
static_assert(\
std::integral_constant<T, false>::value,\
"Second template parameter needs to be of function type.");\
};\
\
\
template<typename C, typename Ret, typename... Args>\
struct has_method_full_signature_ ## NAME <C, Ret(Args...)> {\
template<typename T>\
static constexpr auto check(T*)\
-> typename\
std::is_same<\
decltype( std::declval<T>(). NAME ( std::declval<Args>()... ) ),\
Ret \
>::type; \
\
template<typename>\
static constexpr std::false_type check(...);\
\
using type = decltype(check<C>(0)); \
static constexpr bool value = type::value;\
}
EDIT: add some example code how to use this c-macro stuff here.
#include <utility>
#include <iostream>
#include "component/mytypes_traits.h"
DECLARE_HAS_METHOD_PARMS_ONLY(funny);
DECLARE_HAS_METHOD_FULL_SIGNATURE(f1);
DECLARE_HAS_METHOD_FULL_SIGNATURE(f2);
DECLARE_HAS_METHOD_FULL_SIGNATURE(f3);
class A { public: void funny() {} };
class B { public: void dummy() {} };
class C
{
public:
int f1(int) { return 1;}
float f2(int,int) {return 2.0;}
int f3() { return 1;}
};
int main()
{
std::cout << has_method_parms_only_funny<A>::value << std::endl;
std::cout << has_method_parms_only_funny<B>::value << std::endl;
std::cout << "--" << std::endl;
std::cout << has_method_full_signature_f1< C, int()>::value << std::endl;
std::cout << has_method_full_signature_f1< C, int(int)>::value << std::endl;
std::cout << has_method_full_signature_f1< C, int(int,int)>::value << std::endl;
std::cout << "--" << std::endl;
std::cout << has_method_full_signature_f2< C, float()>::value << std::endl;
std::cout << has_method_full_signature_f2< C, float(int)>::value << std::endl;
std::cout << has_method_full_signature_f2< C, float(int,int)>::value << std::endl;
std::cout << "--" << std::endl;
std::cout << has_method_full_signature_f3< C, int()>::value << std::endl;
std::cout << has_method_full_signature_f3< C, int(int)>::value << std::endl;
std::cout << has_method_full_signature_f3< C, int(int,int)>::value << std::endl;
std::cout << "--" << std::endl;
}
Related
So I've found a variety of articles and posts saying that there is no way to convert typename to string but I haven't found one about the opposite. I have a template of a function with specializations:
template <typename T>
void foo(T sth) {}
template <>
void foo<int>(int sth) {}
...
and I'm reading from a file constructed like this:
int 20
double 12.492
string word
Is there a way to call the correct specialization of foo() depending on the content of the file?
Yes there is, but it requires manual code and that you know all the types that are going to appear in the file. That's because templates are compile time constructs and they cannot be instantiated at runtime.
You can always use the preprocessor or other tricks to try and reduce the boilerplate if you want to.
void callFoo(std::string type, std::any arg) {
if (type == "int")
foo<int>(std::any_cast<int>(arg));
else if (type == "double")
foo<double>(std::any_cast<double>(arg));
else if (type == "string")
foo<std::string>(std::any_cast<std::string>(arg));
}
Of course, this requires that you pass in the correct type (no implicit conversions!). I don't see any way to avoid that.
To be honest, I am not sure about understanding your question. As I interpret it, I believe that you do not need a kind of dispatcher in running time neither to compute a string containing the type name. Simply you write a general template function that calls a special template wrapper that disambiguates the call to foo() according to the type. You require that the specialized foo() receives a second special parameter (the_type<T>) which is used for disambiguating.
Here a full and operating demo:
# include <string>
# include <iostream>
using namespace std;
template<class T> struct the_type { using type = T; };
template <typename T>
void foo(const T par)
{
foo(par, the_type<T>());
}
void foo(int par, the_type<int>)
{
cout << "int " << par << endl;
}
void foo(double par, the_type<double>)
{
cout << "double " << par << endl;
}
void foo(const string & par, the_type<string>)
{
cout << "string " << par << endl;
}
void foo(const char * par, the_type<const char*>)
{
cout << "char* " << par << endl;
}
int main()
{
foo(20);
foo(12.492);
foo("word");
foo(string("word"));
}
whose output is:
int 20
double 12.492
char* word
string word
If you need another specialization, then you simply define it. In some cases, you will have to explicitly to define the specialization as the template parameter.
You could use macro manips for avoiding repetitive things. For example, given that foo() structure is the same, you could encapsulate it in a macro. Something like this:
# define GENFOO(type_name) \
void foo(type_name par, the_type<type_name>) \
{ \
cout << #type_name " " << par << endl; \
}
GENFOO(int);
GENFOO(double);
GENFOO(string)
However, I would say that each specialized version of foo() would not be so similar.
So I've found a variety of articles and posts saying that there is no way to convert typename to string but I haven't found one about the opposite. I have a template of a function with specializations:
template <typename T>
void foo(T sth) {}
template <>
void foo<int>(int sth) {}
...
and I'm reading from a file constructed like this:
int 20
double 12.492
string word
Is there a way to call the correct specialization of foo() depending on the content of the file?
Yes there is, but it requires manual code and that you know all the types that are going to appear in the file. That's because templates are compile time constructs and they cannot be instantiated at runtime.
You can always use the preprocessor or other tricks to try and reduce the boilerplate if you want to.
void callFoo(std::string type, std::any arg) {
if (type == "int")
foo<int>(std::any_cast<int>(arg));
else if (type == "double")
foo<double>(std::any_cast<double>(arg));
else if (type == "string")
foo<std::string>(std::any_cast<std::string>(arg));
}
Of course, this requires that you pass in the correct type (no implicit conversions!). I don't see any way to avoid that.
To be honest, I am not sure about understanding your question. As I interpret it, I believe that you do not need a kind of dispatcher in running time neither to compute a string containing the type name. Simply you write a general template function that calls a special template wrapper that disambiguates the call to foo() according to the type. You require that the specialized foo() receives a second special parameter (the_type<T>) which is used for disambiguating.
Here a full and operating demo:
# include <string>
# include <iostream>
using namespace std;
template<class T> struct the_type { using type = T; };
template <typename T>
void foo(const T par)
{
foo(par, the_type<T>());
}
void foo(int par, the_type<int>)
{
cout << "int " << par << endl;
}
void foo(double par, the_type<double>)
{
cout << "double " << par << endl;
}
void foo(const string & par, the_type<string>)
{
cout << "string " << par << endl;
}
void foo(const char * par, the_type<const char*>)
{
cout << "char* " << par << endl;
}
int main()
{
foo(20);
foo(12.492);
foo("word");
foo(string("word"));
}
whose output is:
int 20
double 12.492
char* word
string word
If you need another specialization, then you simply define it. In some cases, you will have to explicitly to define the specialization as the template parameter.
You could use macro manips for avoiding repetitive things. For example, given that foo() structure is the same, you could encapsulate it in a macro. Something like this:
# define GENFOO(type_name) \
void foo(type_name par, the_type<type_name>) \
{ \
cout << #type_name " " << par << endl; \
}
GENFOO(int);
GENFOO(double);
GENFOO(string)
However, I would say that each specialized version of foo() would not be so similar.
So I've found a variety of articles and posts saying that there is no way to convert typename to string but I haven't found one about the opposite. I have a template of a function with specializations:
template <typename T>
void foo(T sth) {}
template <>
void foo<int>(int sth) {}
...
and I'm reading from a file constructed like this:
int 20
double 12.492
string word
Is there a way to call the correct specialization of foo() depending on the content of the file?
Yes there is, but it requires manual code and that you know all the types that are going to appear in the file. That's because templates are compile time constructs and they cannot be instantiated at runtime.
You can always use the preprocessor or other tricks to try and reduce the boilerplate if you want to.
void callFoo(std::string type, std::any arg) {
if (type == "int")
foo<int>(std::any_cast<int>(arg));
else if (type == "double")
foo<double>(std::any_cast<double>(arg));
else if (type == "string")
foo<std::string>(std::any_cast<std::string>(arg));
}
Of course, this requires that you pass in the correct type (no implicit conversions!). I don't see any way to avoid that.
To be honest, I am not sure about understanding your question. As I interpret it, I believe that you do not need a kind of dispatcher in running time neither to compute a string containing the type name. Simply you write a general template function that calls a special template wrapper that disambiguates the call to foo() according to the type. You require that the specialized foo() receives a second special parameter (the_type<T>) which is used for disambiguating.
Here a full and operating demo:
# include <string>
# include <iostream>
using namespace std;
template<class T> struct the_type { using type = T; };
template <typename T>
void foo(const T par)
{
foo(par, the_type<T>());
}
void foo(int par, the_type<int>)
{
cout << "int " << par << endl;
}
void foo(double par, the_type<double>)
{
cout << "double " << par << endl;
}
void foo(const string & par, the_type<string>)
{
cout << "string " << par << endl;
}
void foo(const char * par, the_type<const char*>)
{
cout << "char* " << par << endl;
}
int main()
{
foo(20);
foo(12.492);
foo("word");
foo(string("word"));
}
whose output is:
int 20
double 12.492
char* word
string word
If you need another specialization, then you simply define it. In some cases, you will have to explicitly to define the specialization as the template parameter.
You could use macro manips for avoiding repetitive things. For example, given that foo() structure is the same, you could encapsulate it in a macro. Something like this:
# define GENFOO(type_name) \
void foo(type_name par, the_type<type_name>) \
{ \
cout << #type_name " " << par << endl; \
}
GENFOO(int);
GENFOO(double);
GENFOO(string)
However, I would say that each specialized version of foo() would not be so similar.
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;
}
First of all I want a normal enumeration instead of a bit-based enumeration, because the amount of different enums will be beyond any integral type. I also want to take advantage of the type safety of C++11 enum class. To do so, the natural choice would be std::bitset, however I have no idea how to bind those two together.
A custom bitset would be needed? How to go around the implementation of such a class?
Since enum classes are wrappers for enums, you can cast them to underlying type. And using some private inheritance you can selectively import some functionalities from C++ stdlib classes without worrying about Liskov's principle. Composition resulted in clearer code. Using these functionalities, we can wrap std::bitset. Following code contains only subset of functionalites, but it can be expanded further.
There's a problem with max value - that you can't get maximum value of enum class (or am I wrong?). So I added EnumTraits. Now users are required to specialize EnumTraits with const value max equal to the max value of enum before class can be used.
#include <bitset>
#include <type_traits>
template<typename T>
struct EnumTraits;
template<typename T>
class EnumClassBitset
{
private:
std::bitset<static_cast<typename std::underlying_type<T>::type>(EnumTraits<T>::max)> c;
typename std::underlying_type<T>::type get_value(T v) const
{
return static_cast<typename std::underlying_type<T>::type>(v);
}
public:
EnumClassBitset() : c()
{
}
bool test(T pos) const
{
return c.test(get_value(pos));
}
EnumClassBitset& reset(T pos)
{
c.reset(get_value(pos));
return *this;
}
EnumClassBitset& flip(T pos)
{
c.flip(get_value(pos));
return *this;
}
};
enum class BitFlags
{
False,
True,
FileNotFound,
Write,
Read,
MaxVal
};
template<>
struct EnumTraits<BitFlags>
{
static const BitFlags max = BitFlags::MaxVal;
};
#include <iostream>
int main()
{
EnumClassBitset<BitFlags> f;
f.flip(BitFlags::True);
f.flip(BitFlags::FileNotFound);
//f.flip(2); //fails to compile
std::cout << "Is False? " << f.test(BitFlags::False) << "\n";
std::cout << "Is True? " << f.test(BitFlags::True) << "\n";
std::cout << "Is FileNotFound? " << f.test(BitFlags::FileNotFound) << "\n";
std::cout << "Is Write? " << f.test(BitFlags::Write) << "\n";
std::cout << "Is Read? " << f.test(BitFlags::Read) << "\n";
}
Since enums don't have much functionality unfortunately, and what is more, C++11 with enum classes don't improve the situation, some programmers use static map wrapped in a class. Definitely a good read.