I want to have initializer_list as a parameter in my function in order to use an undetermined amount of a specific type of variable. It must be a initializer_list because I want to be able to create the list on the function call and because I pass the list into other subfunctions. However, I need to be able to modify the elements in the list and I can't because initializer_list automaticly makes the pointers of type const.
So my question is how do I go about making my own initializer_list class? Making a copy of the header with const removed didn't work and I can't seem to find the answer anywhere.
You can't. std::initializer_list is a magic type that is intricately tied to the compiler, and there is no way to create your own type with the same ability to be constructed from a braced-init-list.
In that sense it's a bit like std::typeinfo and std::nullptr_t. They happen to be defined in namespace std and so appear to be part of the standard library, but they are actually predefined types that are part of the run-time environment and cannot be emulated in pure C++.
I think you might be able to just use a vector.
void foo(std::vector<int> values);
is callable with
foo({ 1, 2, 3, 4 });
and then you can pass (move) the vector around as usual and the elements are modifyable of course.
You can't do this directly. However, I did kind of workaround in my code sometime ago.
First, a slice type which is a non-owning wrapper around contiguous chunk of memory - a pointer to its start and its size.
Second, I added following ctor:
slice(std::initializer_list<T> && list)
: slice((T*)list.begin(), list.size())
{ }
where T is slice's type. This works well on G++ 4.8 and 4.9, though I didn't check it on 5.X versions.
This is definitely a hack, but you'll be able to use slice<T> as function argument, and then (with enough variety of implicit constructors) pass any contiguous container there, including array, vector and initializer_list. With full support for moves.
Hope this helps.
Related
i am making some callback system and i wonder if i can reserve function reference to unordered_map so that i can invoke it later.
float func_imp(float x)
{
return x;
}
int main()
{
using Tumap = unordered_map<int, float(&)(float)>;
Tumap umap;
umap.emplace(0, func_imp);
(umap[0])(10.1); //a reference type cannot be value-initialized
using Tvec = vector<float(&)(float)>;
Tvec uvec; // pointer to reference is illegal
//uvec.emplace_back(func_imp);
}
Is it possible to use this type of containers to reserve callback functions? if not, is it the only way to use function pointer?
Regardless of wether this is something you should be doing or not (the comments under your question are covering this already), it's still worth answering your question as is.
The [] operator of map types is a veritable swiss army knife. You can do a lot of things with it.
You can assign a value.
You can lookup the value.
You can lookup a value even if it doesn't exist yet.
Because of this, using that operator imposes some requirements for whatever type is stored in the map. In this specific case, you are running into the requirement that it has to be value-initializable, which references cannot be.
This applies to regular references as well by the way, not just function references.
So the answer is: You can store references in a map as much as you like as long as you don't use any function of the map that requires the reference to do something it's not allowed to.
In this case, you can use umap.at(0)(10.1);. One of the big differences between [] and at() is that if the key is not set yet, at() will throw an exception instead of creating a value-initialized value.
Is it possible to use this type of containers to ...
Regardless of how this sentence continues: No, it is not possible to use this type of containers. Specifically, element type of no standard container can be a reference. Reference types do not satisfy the requirements that containers have for their element type (at least not when using the standard allocator).
if not, is it the only way to use function pointer?
No, function pointer is not the only way, but it is a way that works.
Other alternatives are function objects such as an erasing function wrapper such as std::function, or a reference wrapper such as std::reference_wrapper.
i just thought there is no need to make dereference.
If you mean syntactically, then I have good news that make your concern irrelevant: There is no need to explicitly indirect through a pointer to function. The indirection is implicit just like with function references. Their call syntax is identical Example:
float(&ref)(float) = func_imp;
float(*ptr)(float) = func_imp;
ref(42.);
ptr(42.);
As such, you needen't worry.
If you are talking about having to indirect through the pointer at runtime at the cost of performance, I have bad news that make your concern irrelevant: References are also a form of indirection just as much as pointers are. They are (typically) not an optimisation.
I have a class that looks like this:
class PasswordCategory
{
public:
PasswordCategory(const std::string&);
~PasswordCategory();
PasswordCategory() = delete;
...
}
This results in a compiler error related to allocators:
error C2280: 'PasswordCategory::PasswordCategory(void)' : attempting
to reference a deleted function File: xmemory0:577
IDE is VS 2013 Community.
I am assuming that this occurs because somewhere else I am using vector of these categories.
std::vector<PasswordCategory> m_categories;
I only insert elements into it using emplace_back(string), however, it seems that the default allocator for PasswordCategory is trying to use the default constructor for PasswordCategory, but since that is deleted, it throws an error.
If I provide the default constructor, it all works fine, but I am wondering how I can mitigate this issue without a default constructor, if at all?
I thought of the following solutions:
Providing a custom allocator for my class that constructs my class. However, this doesn't solve the problem that I want my string argument to be non-optional.
Providing the default constructor that just calls my other constructor with some argument. This also doesn't solve the problem that this argument is non-optional and shouldn't really be defaulted.
Using a vector of references or pointers instead of a vector of values. This seems like the most rational solution, however it introduces the need to manage our memory manually, unless we use unique_ptr or something similiar.
I am wondering if I can somehow prohibit arg-less construction of my class, while still being able to use it in standard containers by value?
Any answers and insights are appreciated, thanks in advance.
P.S. This is for a small project of mine that I am doing in order to better understand C++, where I am trying to avoid most of the common pitfalls and make everything as reliable as possible, so that when I am going to work on a bigger project, it will be easier for me to avoid these common pitfalls. I tried formulating the question in different manners, but didn't find an answer for my question, so instead I'm asking my own one.
std::vector itself doesn't require T to be a DefaultConstructible type:
Until C++ 11:
T must meet the requirements of CopyAssignable and CopyConstructible.
Since C++ 11:
The requirements that are imposed on the elements depend on the actual operations performed on the container. Generally, it is required that element type is a complete type and meets the requirements of Erasable, but many member functions impose stricter requirements.
See this page for details.
You may, however, perform operations on container, that involve creating implicit instances and that's why you get this error. If you can track them and eliminate them, everything should work fine, as default constructor will simply not be required if it is not used.
Considering your proposals:
1. Providing a custom allocator for my class that constructs my class.
This won't help - std::allocator is not responsible for default-contructing elements, because it simply does not define such functionality. See std::allocator::construct.
EDIT
Little mistake here, I didn't noticed small change in C++ 11:
Until C++ 11
void construct( pointer p, const_reference val );
Since C++ 11
template< class U, class... Args >
void construct( U* p, Args&&... args );
2. Providing the default constructor that just calls my other constructor with some argument.
This also doesn't solve the problem that this argument is non-optional and shouldn't really be defaulted.
This is also not fully portable. Some compilers (like VC11) does not support delegating constructors.
3. Using a vector of references or pointers instead of a vector of values.
This seems like the most rational solution, however it introduces the need to manage our memory manually, unless we use unique_ptr or something similiar.
Not quite valid - you can't create container of references. The closest solution would be container, that holds std::reference_wrappers. Container of raw/smart pointer is also an option, but that's the point, where things are started to get messy.
Also, in your original code, there is no need to declare deleted default constructor - if you declare any constructor, it means that there is no default one (unless you define it) and compiler won't generate any.
In principle, you cannot: standard containers require contained objects to be default-constructible. (see comment from Mike Seymour).
In principle you should be able to, unless you use operations that require default construction internally.
That said, you can simply create an empty constructor (that defaults members to something sane/calls another constructor with some arguments). If you write client code correctly, you will not encounter your object, initialized with default values.
The operations that require default construction of objects are usually resize, and a few others that require creating internal objects (i.e. unless you want to reserve an element and use it without initializing it explicitly, you should not have a problem).
EDIT: Before we begin, this question is not about proper usage of std::initializer_list; it is about what should be passed when the convenient syntax is desired. Thank you for staying on topic.
C++11 introduces std::initializer_list to define functions accepting braced-init-list arguments.
struct bar {
bar( char const * );
bar( int );
} dog( 42 );
fn foo( std::initializer_list< bar > args );
foo( { "blah", 3, dog } );
The syntax is nice, but under the hood it is distasteful due to various problems:
They cannot be meaningfully moved. The above function must copy dog from the list; this cannot be converted to move-construction or elided. Move-only types cannot be used at all. (Well, const_cast would actually be a valid workaround. If there's an article about doing so, I'd like to see it.)
There are no constexpr semantics, either. (This is forthcoming in C++1y. It's a minor issue, though.)
const does not propagate as it does everywhere else; the initializer_list is never const but its contents always are. (Because it doesn't own its contents, it cannot give write access to a copy, although copying it anywhere would seldom be safe.)
The initializer_list object does not own its storage (yikes); its relationship to the completely separate naked array (yikes) providing the storage is hazily defined (yikes) as the relationship of a reference to a bound temporary (quadruple yikes).
I have faith these things will be fixed in due time, but for now is there a best practice to get the advantages without hard-coding to initializer_list? Is there any literature about or analysis into working around direct dependency on it?
The obvious solution is to pass by value a standard container such as std::vector. Once the objects are copied into it from the initializer_list, it is move-constructed to pass by value, and then you can move the contents out. An improvement would be to offer storage on the stack. A good library might be able to offer most of the advantages of initializer_list, array, and vector, without even using the former.
Any resources?
it is about what should be passed when the convenient syntax is desired.
If you want the convenience of size (ie: the user just types a {} list with no function calls or words), then you must accept all the powers and limitations of a proper initializer_list. Even if you try to convert it into something else, like some form of array_ref, you still have to have an intermediary initializer_list between them. Which means that you can't get around any of the issues you've run into, like not being able to move out of them.
If it goes through an initializer_list, then you have to accept these limitations. Therefore, the alternative is to not go through an initializer_list, which means that you're going to have to accept some form of container with specific semantics. And the alternative type would have to be an aggregate, so that the construction of the alternate object won't encounter the same problem.
So you're probably looking at forcing the user to create a std::array (or a language array) and passing that. Your function could take some form of array_ref class, which can be constructed from any array of arbitrary size, so the consuming function isn't limited to one size.
However, you lose the convenience of size:
foo( { "blah", 3, dog } );
vs.
foo( std::array<bar, 3>{ "blah", 3, dog } );
The only way to avoid the verbosity here is to have foo take std::array as a parameter. Which means that it could only take an array of a specific fixed size. And you couldn't use C++14's proposed dynarray, because that will use an initializer_list intermediary.
Ultimately, you shouldn't be using uniform initialization syntax for passing around lists of values. It's for initializing objects, not for passing lists of things. std::initializer_list is a class who's sole purpose is to be used to initialize a specific object from an arbitrarily long list of values of identical types. It is there to serve as an intermediary object between a language construct (a braced-init-list) and the constructor that these values are to be fed into. It allows the compiler to know to call a particular constructor (the initializer_list constructor) when given a matching braced-init-list of values.
This is the entire reason why the class exists.
Therefore, you should use the class exclusively for the purpose for which it was devised. The class exists to tag a constructor as taking a list of values from a braced-init-list. So you should use it only for constructors that take such a value.
If you have some function foo that acts as an intermediary between some internal type (that you don't want to directly expose) and a user-provided list of values, then you need to take something else as a parameter to foo. Something that has the semantics you desire, which you can then feed into your internal type.
Also, you seem to have a misconception around initializer_lists and movement. You cannot move out of an initializer_list, but you can certainly move into one:
foo( { "blah", 3, std::move(dog) } );
The third entry in the internal dog array will be move-constructed.
What is the actual benefit and purpose of initializer_list, for unknown number of parameters? Why not just use vector and be done with it?
In fact, it sounds like just a vector with another name. Why bother?
The only "benefit" I see of initializer_list is that it has const elements, but that doesn't seem to be a reason enough to invent this whole new type. (You can just use a const vector after all.)
So, what am I mising?
It is a sort of contract between the programmer and the compiler. The programmer says {1,2,3,4}, and the compiler creates an object of type initializer_list<int> out of it, containing the same sequence of elements in it. This contract is a requirement imposed by the language specification on the compiler implementation.
That means, it is not the programmer who creates manually such an object but it is the compiler which creates the object, and pass that object to function which takes initializer_list<int> as argument.
The std::vector implementation takes advantage of this contract, and therefore it defines a constructor which takes initializer_list<T> as argument, so that it could initialize itself with the elements in the initializer-list.
Now suppose for a while that the std::vector doesn't have any constructor that takes std::initializer_list<T> as argument, then you would get this:
void f(std::initializer_list<int> const &items);
void g(std::vector<int> const &items);
f({1,2,3,4}); //okay
g({1,2,3,4}); //error (as per the assumption)
As per the assumption, since std::vector doesn't have constructor that takes std::initializer_list<T> as argument, which implies you cannot pass {1,2,3,4} as argument to g() as shown above, because the compiler cannot create an instance of std::vector out of the expression {1,2,3,4} directly. It is because no such contract is ever made between programmer and the compiler, and imposed by the language. It is through std::initializer_list, the std::vector is able to create itself out of expression {1,2,3,4}.
Now you will understand that std::initializer_list can be used wherever you need an expression of the form of {value1, value2, ...., valueN}. It is why other containers from the Standard library also define constructor that takes std::initializer_list as argument. In this way, no container depends on any other container for construction from expressions of the form of {value1, value2, ...., valueN}.
Hope that helps.
Well, std::vector has to use initializer_list to get that syntax as it obviously can't use itself.
Anyway, initializer_list is intended to be extremely lightweight. It can use an optimal storage location and prevent unnecessary copies. With vector, you're always going to get a heap allocation and have a good chance of getting more copies/moves than you want.
Also, the syntax has obvious differences. One such thing is template type deduction:
struct foo {
template<typename T>
foo(std::initializer_list<T>) {}
};
foo x{1,2,3}; // works
vector wouldn't work here.
The biggest advantage of initializer_list over vector is that it allows you to specify in-place a certain sequence of elements without requiring delicate processing to create that list.
This saves you from setting up several calls to push_back (or a for cycle) for initializing a vector even though you know exactly which elements are going to be pushed into the vector.
In fact, vector itself has a constructor accepting an initializer_list for more convenient initialization. I would say the two containers are complementary.
// v is constructed by passing an initializer_list in input
std::vector<std::string> v = {"hello", "cruel", "world"};
Of course it is important to be aware of the fact that initializer_list does have some limitations (narrowing conversions are not allowed) which may make it inappropriate or impossible to use in some cases.
Some methods of std::list, and probably other STL containers, have a new overload added in C++11. The one I need is list::splice(). One method takes a list& parameter, the other one takes a list&& parameters.
I'd like to know what the difference, and which ine I should prefer.
I looked at the implementation of libstdc++ (the standard C++ library used by the GCC compiler) and it uses the list&& version in both cases internally. Also the C++11 specification says nothing about this issue. It just offers 2 methods without explaining the difference.
You don't move the list itself, and you don't move the nodes (copying their pointers seems like the way to move nodes from one list to another), so why does it matter? I have just one idea, maybe using list&& is like a promise to the compiler you don't need the other list anymore and the the compiler can save a few operations because it doesn't have to keep the other list valid...
You shouldn't need to care very much. The overload with the std::list&& parameter will be chosen when the argument you pass is an rvalue - usually when the object it refers to is a temporary. You don't need to explicitly say which overload you want to use.
The reason these two versions of the function exist is for convenience, so that the client doesn't have to create a temp std::list variable from the temporary object before passing it to splice (thanks to #HowardHinnent in the comments).
Also, when the list you're splicing from is a temporary object, there's no point caring about maintaining its state. The && version of the function may just rip the guts from that list, leaving a mess all over the floor. This might be done for efficiency (but actually, std::list doesn't have much reason to).
If you have a std::list, other, that you know you'll never use again, you can voluntarily say "I don't care what you do with it", by using std::move:
l.splice(pos, std::move(other));
The expression std::move(other) is an rvalue, so the splice function will treat it as though it were a temporary.
Lvalue references bind to lvalues, and rvalue references to rvalues:
tyedef std::list<Foo> lt;
lt make_list();
int main()
{
lt x;
lt tmp = make_list();
x.splice(tmp); // needs '&'
x.splice(make_list()); // needs '&&'
}