Referring to my previous question, as the explanation is required in detail.
How is the following code snippet working, fundamental and C++ 03 equivalent ?
auto get_option_name = [](const std::pair<const std::string, std::string>& p) -> const std::string& {
return p.first;
};
It's equivalent to:
class Extractor {
// Definition of "function call" operator, to use instance
// of this class like a function
const std::string& operator()(const std::pair<const std::string, std::string>& p) {
return p.first;
}
};
Extractor get_option_name;
More information on wikipedia or on stackoverflow
#Garf365's answer is the best. A lambda and a class like that one really are the most similar - you can use them just like callable functions, and pass around pointers and references to them.
However, you may also want to learn about using function templates to do this work during compile-time, especially when passing them as a parameter to another template, as in using the boost library.
I was curious if there was an improvement in the complexity of the code the compiler produced by using a function template, and there was!
Look for yourself:
Using a "function object" or "functor" class (or whatever they are called) - is 187 lines of assembly from GCC, and 237 lines of assembly from clang.
Using a function template - only 65 lines of assembly from GCC, and 84 from clang. That's a reduction by a factor of 300%!
Thank you for asking the question and leading me to look into it!
Related
I'm experiencing some strange occurrences regarding varidaic templates that I never saw before.
In order to keep it simple i'll give a simple example of what I was trying to achieve, the real code is a bit more involved.
So I have one function that looks like:
template <typename T, typename F, typename ... Args>
static T Func( std::string str, Args&& ... args )
{
... Do something
}
I then call this function a number of times from different locations, where most times the passed types are different. But when I debug this, when I look for the symbol of Func, I get that the same function address has a number of different symbols:
00000000`70ba4ae0 Func<unsigned long,unsigned long (__stdcall*)(wchar_t const *),wchar_t const *>
00000000`70ba4ae0 Func<void *,void * (__stdcall*)(unsigned int),unsigned int>
00000000`70ba4ae0 Func<int,int (__stdcall*)(void *),void *>
So they are all basically the same function. When I try to call for example:
call Func<void *,void * (__stdcall*)(unsigned int),unsigned int>
In the debugger I see:
call Func<int,int (__stdcall*)(void *),void *>
I can see that there is a generated symbol for every template function instance, but every such instance that has the same number of arguments and the arguments are the same byte-size are just linked to one function.
While I can understand why this may happen, but is there a way to force each function to be standalone?
The issue was indeed COMDAT folding. Turning off the OPT:ICF and OPT:REF flags did the trick. Although worth noting that compiling with VS 2017 with the flags produced more "sensible" results than compiling the same code with VS 2013.
Supposing one needs to obtain a logical value based on a
pack of template parameters, is there a reason to prefer an alias approach
vs a function approach?
Example:
template<bool...> struct bool_pack;
template<bool... bs>
using all_true = std::is_same<bool_pack<bs..., true>,
bool_pack<true, bs...>>;
as opposed to
template<class none=void>
constexpr bool all_true() { return true; }
template<bool First, bool... Rest>
constexpr bool all_true() {
return First and all_true<Rest...>();
}
Time required for compiling your example implementations
... should be measured, of course. That said, I have seen micro-benchmarks where the std::is_same approach leads to significantly shorter compile times; even compared to the C++17 fold expression (true && ... && bs) with the respective compilers. The recursive "function approach" you gave as an example should be clearly inferior in compile-time performance.
Note, however, that one could surely offer the most convenient interface by providing a wrapper around the most "efficient" (regarding compile-time effort) implementation.
Convenience in using the "interface"
Given these two choices, I would prefer the alias approach. If you need the result of that helper as a type (for inheritance, template-metaprogramming with specializations, or for tag dispatch), the alias yields cleaner syntax compared to, say, std::bool_constant<all_true_v<some_condition(), some_other_condition()>()>. In the other direction, it is simple to obtain a value of type bool from the alias: all_true<some_condition(), some_other_condition()>{} (relying on implicit type conversion).
Since C++14, yet another (fancy?) choice is to provide a value by a constexpr variable template which has either type std::true_type or std::false_type. By implicit conversion to bool it can readily be used where plain true or false is required, but it can also be passed as a function argument without losing its compile-time guarantee.
template<bool... bs>
constexpr auto all_true_c = typename std::is_same<
bool_pack<true, bs...>, bool_pack<bs..., true>
>::type{};
It may be a good strategy to follow the naming conventions used in the <type_traits> header of modern C++ providing both forms. If some utility is supposed to provide a value, one finds helper variable templates such as std::is_same_v:
template<class T, class U>
inline constexpr bool is_same_v = is_same<T, U>::value;// (since C++17)
if some helper is supposed to provide a type, one finds helper types such as std::decay_t:
template<class T>
using decay_t = typename decay<T>::type;// (since C++14)
... in addition to the conventional utilities without suffix, respectively.
I have a type A that's designed to be implicitly casted to type B. Here's an example case I'd like to use it in:
// Current implementation:
std::transform(vec_of_a.begin(), vec_of_a.end(), std::back_inserter(vec_of_b),
[](const A& a) -> B { return a; }); // Thanks, Kerrek SB.
// Ideal implementation - Won't compile, expected '(' after 'static_cast'.
std::transform(vec_of_a.begin(), vec_of_a.end(), std::back_inserter(vec_of_b),
static_cast<B>);
What can I do to make the latter option compile?
static_cast<B>, while it is invoked with function-call syntax cannot be passed like other callable things. E.g., there's no way to use & to get a function pointer to it.
You can use a short little lambda to achieve something similar to passing a function pointer to static_cast<B>, as you do in your current implementation:
std::transform(vec_of_a.begin(), vec_of_a.end(), std::back_inserter(vec_of_b),
[](const A& a) -> B { return a; });
Another option--in this particular case--would be to construct a vector<B> from the vector<A>:
std::vector<B> vec_of_b(vec_of_a.begin(), vec_of_a.end());
(This answer is a summary of the comments on both the question and bipll's answer.)
Build a functor enclosing static_cast:
template <typename T>
struct StaticCast
{
template <typename U>
T operator()(const U& rhs)
{
return static_cast<T>(rhs);
}
};
With this, you can call std::transform:
std::transform(vec_of_a.begin(), vec_of_a.end(), std::back_inserter(vec_of_b), StaticCast<b>());
It can be used in the case the output vector is already defined in place of the lambda shown in comments. If not, prefer the constructor mentioned in another answer**.
This functor version is compliant with C++98 if needed -- even if OP is tagged C++11, it may be worthy to note this point.
** Note that with this particular constructor, a warning C4244 is raised with VS compiler (tested with VS2017).
Yes, that's the way anonymous functions work in C++, and static_cast is not a function so you cannot pass its address as the mapped function. You'll have to deal with it.
You cannot use a constructor either.
The following code outputs different results on various compilers:
2,1,2 on Visual Studio 2013
2,2,2 on Visual Studio 2015
2,1,1 on GCC5/c++14
2,2,2 on Clang 3.7 with Microsoft Codegen
2,1,2 on Clang 3.6/c++11 under Ubuntu 14.04
Finally, how it should work according to C++ standard?
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
class Value;
using Array = std::vector<Value>;
class Value
{
public:
Value(const Array &)
{
}
Value(int)
{
}
};
void foo(Array const& a)
{
printf("%d\n", (int)a.size());
}
int main()
{
Array a1 = { 1, 2 };
foo(a1);
foo(Array{ a1 });
foo(Array({ a1 }));
}
P.S. The same issue reveals with json_spirit library from this article: http://www.codeproject.com/Articles/20027/JSON-Spirit-A-C-JSON-Parser-Generator-Implemented
Your program is ill-formed in C++11, as you have created a std::vector type with an incomplete type as an argument. The value type of a vector must be complete when you create the std::vector<T> type.
As an ill-formed program (and I'm not aware of a requirement for a diagnostic), any and all behavior is legal under the standard.
The requirement that vector's T be a complete type is probably over-specified (there is really no convincing reason to have that requirement), but it exists. Asking the same question in C++1z will lead to a different answer, as that requirement was relaxed.
Ignoring that issue, philosophically:
Array a1 = { 1, 2 };
this should generate a std::vector with two elements.
foo(a1);
This should pass a1 to foo, as the types match exactly.
foo(Array{ a1 });
Here we have {}. My rule of thumb with {} is "if it is non-empty, and it can match an initializer_list constructor, it must".
As a1 can be converted to a Value, Array{ a1 } is an array of one Value.
foo(Array({ a1 }));
Here we look at an argument of the constructor Array that can be called with { a1 }. Both the std::initalizer_list<Value> and the Array&& constructors can be.
Which is called should not matter: The Array&& constructor in turn sends the {a1} to the std::initalizer_list<Value> constructor.
So my opinion is that it should print 211. This is, however, merely an opinion on what the could ought to do, not an analysis of what the standard says it should do, as the C++11 standard quite clearly states your program is ill-formed.
On the other hand, hiding the copy constructor seems rude.
On the final hand, you did write a simply insane type. Insane behavior is to be expected.
A more practical concern might be when the Value type has a template constructor that happens to also match a std::vector<Value>.
In C++11, compilers' determination to match braced initializers with constructors taking std::initializer_lists is so strong, it prevails even if the best-match std::initializer_list constructor can't be called (Scott Meyers).
Array a1 = { 1, 2 }; // Call Initiliazer list constructor foo(a1); // print 2
foo(Array{ a1 }); // Call Initiliazer list constructor. Print 1
foo(Array({ a1 })); // Call Initiliazer list constructor. Print 1
According to the standard, the result must be: 2,1,1
Yakk's answer mention that the program is ill-formed in C++11. But this post is very interesting.
I would like to store some closures in an array.
I tagged the question MSVC10 since it seems that according to c++11 closures should be compatible (at least under some conditions) with function pointers but MSVC10 does not supports that.
Is there a way around this limitation?
example:
typedef double (*Func)(const C* c);
struct Feature{
Feature(FeatureId i_id = None, const QString& i_name=QString(), Func i_ex = nullptr)
:id(i_id),name(i_name), extraction(i_ex)
{}
FeatureId id;
QString name;
Func extraction;
};
QList<Feature> features;
features.append(Feature(feat_t, "a/t", [](const C* c) -> double{return c->a.t;} ));
I want to be able to assign closures to the function pointer because i do not want to define dozens of separate functions.
Thanks in advance for your suggestions.
You should use std::function<double(const C*)> (see this) instead of Func, so
struct Feature{
FeatureId id;
QString name;
std::function<double(const C*)> extraction;
/// etc...
};
You may need to upgrade your compiler (I guess that Visual Studio 2010 appeared before the C++11 standard, but I never used Windows or other Microsoft products). Did you consider using a recent GCC (4.9 at least) or a recent Clang/LLVM (3.5) ?
If you cannot upgrade your compiler, stick to C++98 and don't use C++11 features.
By definition, a closure is more heavy that a function pointer, since it contains closed values (some of which might be hidden or non-obvious).