I have the following C++ snippet:
template_par<std::string> a("name", "Joh Node");
template_par<int> b("age", 23);
std::string result = templater<SomeTemplateClass>().templatize(a, b).get();
Which tries to implement a template engine for various purposes. The important parts of the templater class are:
template<class T>
class templater
{
std::map<std::string, std::string> kps;
public:
template <typename T1>
templater& templatize(template_par<T1> b)
{
kps.insert(make_pair(b.getKey(), to_string(b.getValue())));
return *this;
}
template<typename T1, typename... Args1>
templater& templatize(T1 first, Args1... args)
{
kps.insert(make_pair(first.getKey(), to_string(first.getValue())));
return templatize(args...);
}
}
ie. a template function with variable arguments .... template_par<T> are just template parameter classes for basic stuff. Right now as it is, this works, does the job nicely.
However, I would like to be able to shorten somehow the way I call the templatize method not only for aesthetics but also for a challenge... I think it would look much nicer something like:
std::string result = templater<SomeTemplateClass>().templatize(
"name" -> "Joh Node",
"age" -> 42
);
However this approach is not feasible due to the operator -> being a somewhat rigid piece of C++ ... (std::string result = templater<SomeTemplateClass>().templatize is not the important part here, that can be hided in a friendly construct, I am more worried about the variable number of parameters)
Any good beautification ideas for the challenge above?
Take a look at Boost.Assign, in particular the map assignment part of it, which you could co-opt here:
std::string result = templater<SomeTemplateClass>()
("Name", "Joh Node")
("Age", 42).templatize();
I would avoid getting much more creative than that, it makes the code cryptic. That said, if you want to experiment wildly, you might like my named operators, which would allow syntax such as:
std::string result = templater<SomeTemplateClass>().templatize(
"name" <is> "Joh Node",
"age" <is> 42
);
Here, is can be any valid C++ identifier. So conventional operators are unfortunately out, but pretty much everything flies. Even, if you really want to push it, <_>.
Related
In my work's codebase, I see the following
class custom {
auto set_data_type(custom_type_t type_t) -> custom & {
// set some stuff
// return *this;
}
}
Why can't we simply just do
class custom {
custom & set_data_type(custom_type_t type_t) {
// set some stuff
// return *this;
}
}
What is the point of using auto in this case when you already know the return type and already wrote it out in the ->... place?
It seems auto would only be beneficial if it is used with decltype(arg) and where arg may have varying return types?
I would say style.
Moreover, it allows to be consistent in any contexts,
simple one (as this one),
more useful ones ("complex" decltype(arg) , scoping (-> iterator instead of typename C::iterator)
or required one (lambda).
To me the most use of this feature is when you're using nested type when defining a function body in a cpp file:
class MyLongClassName
{
using ANestedType = ...;
ANestedType myFunction();
}
When you implement to function body, this syntax avoid some repetition:
MyLongClassName::ANestedType MyLongClassName::myFunction()
{ ... }
versus
auto MyLongClassName::myFunction() -> ANestedType
{ ... }
I believe, "auto" should not be used at all. IMHO, this is ugly sibling of void*; it hides types from programmer, while it is better to know exactly what type is used; this makes one's programming style clumsy, confuses and invites bugs. While the only "reasonable" use of this is typename "shortening", it is actually ridiculous, because short type names don't need to replaced, and for long names there is another keyword. IMHO.
On this subject, I have read few relevant SO questions/answers/comments. Found only one relevant but somewhat buried question/answer here. Allow me to try and clearly show the issue in question/answer manner. For the benefit of others.
Let the code speak. imagine you design this template.
// value holder V1.0
// T must not be reference or array or both
template<typename T> struct no_arrf_naive
{
static_assert(!std::is_reference_v<T>, "\n\nNo references!\n\n");
static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");
using value_type = T;
T value;
};
Simple and safe, one might think. Some time after, other folks take this complex large API, where this is buried deep, and start using it. The struct above is deep inside. As usually, they just use it, without looking into the code behind.
using arf = int(&)[3];
using naivete = no_arrf_naive<arf>;
// the "test" works
constexpr bool is_ok_type = std::is_class_v< naivete >;
// this declaration will also "work"
void important ( naivete ) ;
But. Instantiations do not work
naivete no_compile;
static assert message does show all of a sudden. But how has the "test" compiled and passed? What is going on here?
The issue is that API is wrong. static_assert as class member does "kick-in" but not before instantiation.
First the offending API commented
template<typename T>
struct no_arrf_naive
{
// member declarations
// used only on implicit instantiation
// https://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
static_assert(!std::is_reference_v<T>, "\n\nNo references!\n\n");
static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");
using value_type = T;
T value;
};
Users are here properly coding to transform from Template to Type, but, static_assert's do not kick-in:
using naivete = no_arrf_naive<arf>;
This might most worryingly go on unnoticed, until someone wants to use this. That will not compile and the message, API author has placed in there, will show at last. But alas, too late.
And on projects laboring on some large C++ source, problems that show up late, are the most notorious ones.
The solution is good old SFINAE. The API fixed is this:
// value holder
// references or arrays or both are excluded at compile time
template<typename T,
std::enable_if_t<
(!std::is_reference_v<T> && !std::is_array_v<T>), bool> = true
> struct no_arrf
{
using value_type = T;
T value;
};
The above will not compile immediately upon trying to create the type from template with either reference or array or both:
// reference to array of three int's
using arf = int(&)[3] ;
// no can do
using no_naivete = no_arrf<arf>;
(MSVC) error C2972: 'no_arrf':
template parameter 'unnamed-parameter':
the type of non-type argument is invalid
I might think this whole story might look like trivial or even useless to some. But, I am sure many good folks are coming to SO for badly needed standard C++ advice. For them, this is neither trivial nor useless.
Many thanks for reading.
I hope some one can help me a little here. I am relatively new to C++ and also to the concept of Templates.
I need to create a std::function based on some data that I am getting in a list.
The signature of the function should be according to the data available. I am looking for something like this
template <typename ret, typename... Args, typename newArg>
struct typeparser<ret(...Args)>{
typeparser<ret(...Args)> insertArg(newArg)
{
retrun typeparser <ret(...args, newArg) > ;
}
};
What I want to do is iterate through a vector of boost::variant and then based on the type of value i see, add it to the list of parameters once complete, create a std:function and load it from a lib, then execute it. Make any sense?
std::vector<boost::varient<int, char, std::string>> list;
arglist = typeparser<int()>; //all functions have int return, so start with return int and 0 args
for(boost::varient<int, char, std::string> a : list) {
if(a.type() == typeid(int)){
arglist.addArg(int); // now add int to list of args
} else
if(a.type()== typeid(char)) {
arglist.add(char);
} else
if (a.type()== typeid(bla)) {
arglist.add(bla);
}
} // end for
//now create the function here
std::function<arglist> f = //load from library;
Does this even seem possible? Maybe I am looking at the problem in the wrong way? Any thing will help at this time.
Thanks a lot!!
A std::function must have all its parameters specified at compile time -- what you're asking for would require the set of parameters not be known until runtime which is not allowed.
It would be theoretically possible to make what you're proposing by having something like std::function that contained a stack of parameters to call or something like that, but I don't believe that there is a portable way to do it.
It sounds like you would be better off asking for a solution to the problem you need this "runtime std::function" for.
I have an application which has a lot of functions which go through all the elements of a menu toolbar.
The code looks like something like this:
subMenuDefaultMenuShortcuts( ui->fileMenu );
subMenuDefaultMenuShortcuts(ui->editMenu);
subMenuDefaultMenuShortcuts(ui->windowMenu);
subMenuDefaultMenuShortcuts(ui->helpMenu);
subMenuUpdateLabels(ui->fileMenu,hierarchy);
subMenuUpdateLabels(ui->editMenu,hierarchy);
subMenuUpdateLabels(ui->windowMenu,hierarchy);
subMenuUpdateLabels(ui->helpMenu,hierarchy);
It is possible i will change this implementation, or menus could have sub menus. Thus search and replacing code, is not only ugly, but also hardly readable and error prone.
ideally i whould want something like this:
OnAllMenus(functionName,params ...)
so my code whould look like:
OnAllMenus(subMenuUpdateLabels)
OnAllMenus(subMenuUpdateLabels,hierarchy)
OnAllMenus(someFunction,hierarchy,argument1,argument2)
I wanted to use macro, but their usage is not recommended.
Howerver using inline functions with function pointers seems to lead to some hardly readable code. (And i did not see any example with function pointers expecting variable number of arguments with a function).
Is there any better / cleaner way to do it without addind some overly complex unmaintanable code.
template<typename FuncPointer, typename ... Args>
void for_all_menus(FuncPointer func, Args ... args)
{
f(ui->foo,std::forward<Args>(args)...);
f(ui->bar,std::forward<Args>(args)...);
// etc
}
// use
for_all_menus(&subMenuLabel, hierarchy);
Pmr's answer, but variadic templates to stop the stupid boost::binds that will be scattered everywhere.
You can use boost::function and boost::bind.
template<typename Func>
void for_all_menus(Func f) {
f(ui->foo);
f(ui->bar);
// etc
}
// use
for_all_menus(boost::bind(subMenuLabel, _1, hierarchy));
// with variadic templates
template<typename Func, typename Args...>
struct for_all_menus {
Func f;
void operator()(Args&&... args) {
// umh, I always mess up the syntax
// you might want to double check this
f(ui->foo, std::forward<Args>(args)...);
}
};
template<typename F>
for_all_menus<F> make_for_all_menus(F f) { return for_all_menus<F>{f}; }
// use
auto f = make_for_all_menus(subMenuLabel);
f(hierarchy);
If you need something more dynamic simply replace the function
template with a function that takes a boost::function. Of course you
can also use the C++11 equivalents and lambdas.
If you want to get the list of menus into one place and use that list
in different places, I'd recommend Boost.Preprocessor. But you might
want to think twice before resorting to it.
Okay, this is just a minor caveat. I am currently working with the lovely ArcSDK from ESRI. Now to get a value from any of their functions, you basically have to pass the variable, you want to assign the value to.
E.g.:
long output_width;
IRasterProps->get_Width(&output_width);
Its such a minor thing, but when you have to pick out around 30 different pieces of data from their miscellaneous functions, it really starts to get annoying.
So what i was wondering is it possible to somehow by the magic of STL or C++ change this into:
long output_width = IRasterProps->get_Width(<something magical>);
All of the functions return void, otherwise the off chance some of them might return a HRESULT, which i can safely ignore. Any ideas?
***EDIT****
Heres the final result i got which works :)!!!!!
A magic(P p, R (__stdcall T::*f)(A *)) {
A a;
((*p).*f)(&a);
return a;
}
I know I've already answered, but here's another way. It's better in that it's faster (no boost::function overhead) and avoids the binders (since people seem to have an aversion to them), but is worse in that it's much less general (since it only works for one-argument member functions).
template <typename P, typename T, typename A>
A magic(P p, void (T::*f)(A &)) {
A a;
((*p).*f)(a);
return a;
}
Which you'd call like this:
long output_width = magic(raster_props_object, &IRasterProps::get_Width);
Or, if you happen to be using GCC, we can use some more tricks:
#define MORE_MAGIC(p,f) ({ \
typedef __typeof(*(p)) big_ugly_identifier; \
magic((p),(&big_ugly_identifier::f)); \
})
Which will let us do this:
long output_width = MORE_MAGIC(raster_props_object, get_Width);
(Bonus points if the naming conventions made you think of a PDP-10.)
EDIT: Updated to take any pointer-like type, so it will now work with shared_ptr, iterators, and hopefully _com_ptr.
EDIT: Oops, they're pointers, not references. Here's a version (or overload) that deals with that, and allows -- by ignoring -- arbitrarily-typed return values.
template <typename P, typename T, typename A, typename R>
A magic(P p, R (T::*f)(A *)) {
A a;
((*p).*f)(&a);
return a;
}
This is not quite what you specified because you need to wrap get() around the method, but it works:
template<class T, class S>
T get(S fun(T&)) {
T result;
fun(result);
return result;
}
void foo(int& x) {
x = 5;
}
bool bar(char& x) {
x = 'c';
return false;
}
int main() {
int x = get(foo);
char y = get(bar);
return 0;
}
Can you derive from IRasterProps? Being that the case you can construct your own interface to it.
EDIT: Following on the concept you can probably also apply the Adapter design pattern (or even a Facade if you wish to apply a common interface to several like-minded classes of the SDK).
Looks like a COM object to me.
Visual C++ supports an #import directive to import the type library, and create high-legel wrappers. So you either end up with
width = ptr->GetWidth();
or - even better -
width = ptr->Width;
If a function fails, the HRESULT returned will be transformed into an _com_error exception.
I've used that successfully on many OS and 3rd party COM objects, makes them much easier to use.
Note that you control the wrapper generation through options, the first thing I do is usually adding a rename_namespace or no_namespace, because otherwise the symbold end up in a namespace depending on the typelib name, which is usually ugly.
also, unless you use named_guids option, you might needto change CLSID_xxx and IID_xxx constants to __uuidof(xxx).
EDIT: In retrospect, I'm not sure this one will actually work, since I don't think the template arguments will deduce. Buyer Beware.
Sure! What you need is something to which you can pass a function that will call it and return you the outputted value.
Here's the easy, if less efficient way:
template <typename T>
T magic(boost::function<void(T&)> f) {
T x;
f(x);
return x;
}
Which you'd then call like this using boost::lambda:
long output_width = magic(raster_props_object->*&IRasterProps::get_Width);
Or like this, using boost::bind:
long output_width = magic(bind(&IRasterProps::get_Width, raster_props_object, _1));
You can get rid of boost::function, but that's uglier. Probably worth it, though.
Don't think this is possible. Assigning void to a long should be an error in any case.
Remember, it's probably more performant to pass-by-reference than to return a large object. (won't really make a difference with long's though)
Compiling this:
void foo(long &a) {
}
int main(void) {
long a=0;
a = foo(a);
return 0;
}
gives this error:
g++ x.cc
x.cc: In function ‘int main()’:
x.cc:9: error: void value not ignored as it ought to be
I'm not aware of something insane you could do, precisely like you're asking, and if there was some insane hackery that did work on some peculiar platform I'm pretty sure in a code-review I'd hate it.
It may may more sense to either...
define some trivial inline function wrappers around the APIs you care about
make a specialized class descend from IRasterProps (or whatever) that provides the appropriate accessor methods.
Either of those will impact maintenance time of the code but would safely and cleanly give you the call syntax you are looking for.