I think, it can be an interesting exercise. It should not be to difficult to do and you are not limited by built-in type only. There is a well know stringification pp-operation:
#include <iostream>
#define literal_builder(a) std::cout<<#a<<std::endl;
int main()
{
int a;
literal_builder(a);
}
So here you create a string literal (== branch name) out of identifier. There is no other good way to have
a bridge between “compiler-world-entity” (identifier, identifier-name) and “runtime-entity” (string, which you pass as an argument).
The only thing, of course, it’s still error-prone - what if you have a “typo” when naming identifier?
Anyway, the really good generic library-quality solution must care about checking names at a runtime at least.
The next step is to create a “type description” part like “a/I” out of name and a type. And this will be a bit more difficult - since #macro_parameter_name is a pp-part of translation, but the type of variable exists only in a completely different phase of translation and you have to concatenate them somehow. Something like:
#include <iostream>
#include <string>
template<class T>
struct Type2Literal;
template<>
struct Type2Literal<int>
{
constexpr static const char * const typeName = "/I";
};
#define literal_builder(a) std::cout<<#a<<std::endl;
#define typed_literal_builder(a) std::cout<<std::string(#a) + Type2Literal<decltype(a)>::typeName<<std::endl;
int main()
{
int a;
literal_builder(a);
typed_literal_builder(a);
}
This code requires -std=c++11 to compile. May be it’s too verbose, it’s just a sketch/idea (I mainly program Objective-C these days, so my C++ is bit out of date )
P.S. I think, I can participate in creating such a macro/function if you want
P.P.S.
The solution without decltype/constexpr etc. is also quite simple (still must be compiled e.g. ACLiC):
#include <iostream>
#include <string>
//We need some template magic instead of simple functions to
//suppress implicit type conversions (thus wrong type suffix).
template<class T>
struct InvalidConversion;
template<>
struct InvalidConversion<int>
{};
template<>
struct InvalidConversion<double>
{};
inline const char * type_suffix(InvalidConversion<int>)
{
return "/I";
}
inline const char * type_suffix(InvalidConversion<double>)
{
return "/D";
}
template<class T>
const char * type_suffix(T a)
{
return type_suffix(InvalidConversion<T>());
}
#define literal_builder(a) std::cout<<#a<<std::endl;
#define typed_literal_builder(a) std::cout<<std::string(#a) + type_suffix(a)<<std::endl;
int main()
{
int a;
literal_builder(a);
typed_literal_builder(a);
//short unsigned s = 0;//check, that we do not generate "/I" for short unsigned int!
//typed_literal_builder(s);
}
P.P.P.S
And finally:
#include <iostream>
#include <string>
//We need some template magic instead of simple functions to
//suppress implicit type conversions (thus wrong type suffix).
template<class T>
struct InvalidConversion;
template<>
struct InvalidConversion<int>
{};
template<>
struct InvalidConversion<double>
{};
inline const char * type_suffix(InvalidConversion<int>)
{
return "/I";
}
inline const char * type_suffix(InvalidConversion<double>)
{
return "/D";
}
template<class T>
const char * type_suffix(T a)
{
return type_suffix(InvalidConversion<T>());
}
#define literal_builder(a) std::cout<<#a<<std::endl;
#define name_with_type_suffix(a) (std::string(#a) + type_suffix(a)).c_str()
class TTree {
public:
void Branch(void *, const char *branchName, const char *branchNameTyped)
{
std::cout<<"branch: "<<branchName<<' '<<branchNameTyped<<std::endl;
}
};
//Now, the ugly part: this is the solution for
#define auto_branch1(tree, a) (tree)->Branch(&a, #a, name_with_type_suffix(a));
#define auto_branch2(tree, a, b) \
auto_branch1(tree, a) \
auto_branch1(tree, b)
#define auto_branch3(tree, a, b, c) \
auto_branch2(tree, a, b) \
auto_branch1(tree, c)
#define auto_branch4(tree, a, b, c, d) \
auto_branch3(tree, a, b, c) \
auto_branch1(tree, d)
int main()
{
TTree tree;
int a = 0, b = 0, c = 0;
double d = 0., e = 0., f = 0.;
auto_branch1(&tree, a);
std::cout<<"-------------\n";
auto_branch1(&tree, d);
std::cout<<"-------------\n";
auto_branch2(&tree, a, d);
std::cout<<"-------------\n";
auto_branch2(&tree, d, e);
std::cout<<"-------------\n";
auto_branch3(&tree, a, e, c);
std::cout<<"-------------\n";
auto_branch4(&tree, a, b, c, d);
}
I’m afraid ugly “macro-magic” is inevitable, you need a macro for “#name conversion”
But this is just an idea. I think, there are a lot of examples, how you can create a “generic” macro (hiding
all these auto_branchN and using variadic macros - either GNU extension or a C++11 feature).