Brace-enclosed initializer list constructor
It can only be done for aggregates (arrays and certain classes. Contrary to popular belief, this works for many nonpods too). Writing a constructor that takes them is not possible.
Since you tagged it as "C++0x", then this is possible though. The magic words is "initializer-list constructor". This goes like
Phenotype(std::initializer_list<uint8> c) {
assert(c.size() <= std::size(m_array));
std::copy(c.begin(), c.end(), m_array);
}
// used like
Phenotype p1{1, 2, 3};
Phenotype p2({1, 3, 2}); // works too
Phenotype p3(1, 2, 3); // doesn't work
However, such initialization will default construct the array and then use the assignment operator. If you aim for speed and safety (you get compile time errors for too many initializers!), you can also use an ordinary constructor with a variadic template.
This can be more generic than needed though (often an initializer_list completely suffices, especially for plain integers). It benefits from perfect forwarding, so that an rvalue argument can be move constructed into an array element
template<typename ...T>
Phenotype(T&&...t):m_array{ std::forward<T>(t)... } {
}
// used like
Phenotype p1{1, 2, 3};
Phenotype p2(1, 2, 3); // works too
Phenotype p3({1, 2, 3}); // doesn't work
It's a hard choice!
Edit Correction, the last one works too, as we didn't make the constructor explicit
, so it can use the copy constructor of Phenotype
, constructing a temporary Phenotype
object and copy it over to p3
. But that's not what we really would want the calls to be :)
Automatic generation of a brace-enclosed initializer list in C++ using language features (NOT pre-processor directives)
Like this:
#include <array>
#include <memory>
#include <utility>
template <std::size_t ...I>
std::array<std::shared_ptr<int>, sizeof...(I)> foo(std::index_sequence<I...>)
{
return {(void(I), std::make_shared<int>())...};
}
std::array<std::shared_ptr<int>, 4> array_ = foo(std::make_index_sequence<4>());
Guaranteed copy elision from C++17 ensures that the array is constructed in place, and no extra moves happen.
The return statement expands to {(void(0), std::make_shared<int>()), (void(1), std::make_shared<int>())...}
. void(...)
is not strictly necessary, but Clang emits a warning otherwise.
But if it was my code, I'd write a more generic helper instead:
#include <utility>
template <typename R, typename N, typename F, N ...I>
[[nodiscard]] R GenerateForEach(std::integer_sequence<N, I...>, F &&func)
{
return {(void(I), func(std::integral_constant<N, I>{}))...};
}
template <typename R, auto N, typename F>
[[nodiscard]] R Generate(F &&func)
{
return (GenerateForEach<R, decltype(N)>)(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
}
Then:
auto array_ = Generate<std::array<std::shared_ptr<int>, 4>, 4>([](auto){return std::make_shared<int>();});
While the lambda discards the index in this case, it often ends up being useful, especially given that in [](auto index){...}
, index.value
is constexpr.
Initialize a class with brace-enclosed initializer list
Initializer lists are more appropriate for situations where the size of the list is dynamic. In your case, where the size of Vec
is a template parameter (i.e. static), you're probably better off with variadic parameters:
template <unsigned C>
struct Vec
{
Vec(){}
template<typename ... V>
Vec(V ... args)
{
static_assert(sizeof...(V) == C, "");
//...
}
};
then these will work:
Vec<3> myVec2;
myVec2 = {1, 2, 3};
Vec<3> myVec3 = {1,2,3};
But this one won't, as it explicitly requires an std::initializer_list
:
Vec<3> myVec1{{1,2,3}};
How to pass in a brace-enclosed initializer list to a function?
Braced-init-list has no type and cause template argument deduction failing.
Non-deduced contexts
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
- The parameter P, whose A is a braced-init-list, but P is not std::initializer_list, a reference to one (possibly cv-qualified), or a reference to an array:
You can specify the template argument as std::initializer_list
explicitly to bypass the deduction,
sayIt<std::initializer_list<std::string>>({"foo", "bar"});
Or add another overload taking std::initializer_list
.
template <typename T>
void sayIt(std::initializer_list<T> stuff) {
sayIt<decltype(stuff)>(stuff);
}
call constructor of class with brace enclosed initilizer list
There's actually more constructors in your question than you let on. Here's two more, courtesy of your compiler:
A(A const&) = default;
A(A &&) = default;
Now the interesting bit is what happens when you write another initializer, A{1, 2, 3}
. That calls your first user defined c'tor. Nothing novel there. But when you write A({1, 2, 3})
, overload resolution has two options. Either construct a temporary A{1, 2, 3}
and copy it. Or construct a vector for the other user provided c'tor.
In both cases it's a user defined conversion sequence. Neither is better than the other, so you get a nice flashing error due to ambiguity.
The solution? Either use brace initialization A{{1,2,3}};
or supply an initializer_list constructor, to better match the initializer list argument.
array initialization requires a brace-enclosed initializer list
If you have access to a C++11 compiler, here's one solution.
Remove the (
and )
from the initializer of value. Use:
Matrix4x4::Matrix4x4(T aa, T ba, T ca,
T ab, T bb, T cb,
T ac, T bc, T cc)
: value{ { aa, ba, ca, 0 },
{ ab, bb, cb, 0 },
{ ac, bc, cc, 0 },
{ 0, 0, 0, 1 } }
{
}
Brace-enclosed initializer for matrix constructor fail in type std::complex double
Your problem is not related to the initializer list. The problem is that this code
#include <iostream>
#include <complex>
int main()
{
std::complex<double> x = (1,2);
std::cout << x;
}
Is not doing what you expect it to do. Output is
(2,0)
Because (1,2)
is the comma operator at work. std::complex<double> x = (1,2);
is the same as std::complex<double> x = 2;
.
You need to use curly braces for initialization:
#include <iostream>
#include <complex>
int main()
{
std::complex<double> x = {1,2};
std::cout << x;
}
Output
(1,2)
PS I would strongly advise you to use a std::vector<T>
to hold the data rather than a T*
. Currently copying a xxx
will cause undefined behavior, due to not following the rule of 3/5.
Related Topics
How to Get Memory Usage Under Windows in C++
What Is "Pch.H" and Why Is It Needed to Be Included as the First Header File
Behaviour of Malloc with Delete in C++
When and How to Use Gcc's Stack Protection Feature
Which C++ Standard Is the Default When Compiling with G++
Why Is the New Random Library Better Than Std::Rand()
How to Cin Values into a Vector
Error with Multiple Definitions of Function
Loading 8 Chars from Memory into an _M256 Variable as Packed Single Precision Floats
Installing C++ Libraries on Os X
How to Use Boost Bind with a Member Function