Initialize parameter into constructor, other than the first one - c++

I want to explicitly change the second parameter in a constructor of a struct, in the following scenario. Is it possible, if so, how?
struct foo{
int x;
int y;
foo(int a=4, int b=6){
x=a;
y=b;
}
};
int main(){
foo *f = new foo();
cout<<f->x<<" "<<f->y<<endl;
//4 6
foo *g = new foo(3,4);
cout<<g->x<<" "<<g->y<<endl;
//3 4
foo *h = new foo(3);
cout<<h->x<<" "<<h->y<<endl;
//3 6
//Can something like this be
//done in C++, if I want
//to change the value of the
//second variable only
foo *k = new foo(b = 13);
return 0;
}

Is it possible, if so, how?
It is not possible with constructor. In general, c++ does not support named keyword arguments to functions, and it is not possible to skip arguments even if they have a default, if you want to pass a non-default after it.
It will be possible without constructor using list initialisation syntax since C++20 using designated initialisers, if you use default member initialisers:
struct foo{
int x = 4;
int y = 6;
};
int main(){
foo f {.y = 4};
}
You can achieve something similar with tag dispatching; No need for future standard:
struct foo{
int x = 4;
int y = 6;
enum Xtag { Xinit };
enum Ytag { Yinit };
foo(int a, int b) : x(a), y(b) {}
foo(Xtag, int a) : x(a) {}
foo(Ytag, int b) : y(b) {}
};
int main(){
foo f(foo::Yinit, 4);
}
A solution using lambda that can be used without modifying an existing class. Following works with your definition of foo:
auto make_foo_x4 = [](int b) {
return foo(4, b);
};
foo f = make_foo_y(4);
The downside is that we have to explicitly repeat the default value of x, so this can break assumptions if the default is changed in class definition.

Related

How I can keep aggregate initialization while also adding custom constructors?

If I don't define a constructor in a struct, I can initialize it by just picking a certain value like this:
struct Foo {
int x, y;
};
Foo foo = {.y = 1};
But if I add new default constructor then I lose this feature:
struct Bar {
int x, y;
Bar(int value) : x(value), y(value) {}
};
Bar bar1 = 1;
Bar bar2 = {.y = 2}; // error: a designator cannot be used with a non-aggregate type "Bar"
Is it possible to have both ways?
I tried adding the default constructor Bar () {} but it seems to not work either.
You can't have your cake and eat it too. If the object has a constructor it is no longer an aggregate, and only aggregates can be initialized with designated initializers. You can't use constructors for arbitrary initialization logic with aggregates.
Are we toasted though? No, because there's the "named constructor" idiom. It's essentially just a static member function that returns an initialized object, and able to perform some logic. The idiom is compatible with aggregate initialization.
struct Foo {
int x, y;
static Foo filled_with(int value) {
return {.x = value, .y = value};
}
};
Foo foo = {.y = 1}; // Still an aggregate.
Foo foo2 = Foo::filled_with(2); // Custom logic
There's not even any copying or moving with this approach, because C++17 removed the possibility for those. foo2 is initialized directly with whatever the static member does.
Similar to what ellipticaldoor wrote:
struct FooBase {
int x = 0, y = 0;
};
struct Foo : FooBase {
Foo(int x_) : FooBase{.x = x_} { }
Foo(FooBase &&t) : FooBase{t} {}
};
Foo foo = {{.y = 1}};
Foo foo2{1};
So far this is the closest thing I can find:
struct Vec2 {
int x, y;
};
struct Bar {
int x, y;
Bar(int value) : x(value), y(value) {}
Bar(Vec2 value) : x(value.x), y(value.y){};
};
Bar bar1 = 1;
Bar bar2 = {{.y = 2}};
But you need to use double params
You can use a data member initializer instead so the type remains an aggregate:
struct Foo {
int x = 0, y = x;
};
Foo foo1 = {.y = 6}; // Foo{0, 6}
Foo foo2{7}; // Foo{7, 7}
(Though it can't be implicitly constructed from int)

parameter list type error in lambda function

I'm not very familiar with lambda expressions C++11. I was trying to simply invoke a method from another class taking an integer and constructing a lambda expression but I'm receiving an error about the parameter not being the correct datatype.
class A{
int _a;
void f(int a){
_a = a;
}
};
class B{
B(){
A instance = new A();
instance.f(
[&](int input)->int
{
int x = 2;
return x;
});
};
}
A lambda is really just a compact way of writing a function.
The lambda in question:
[&](int input) -> int
{
int x = 2;
return x;
};
is a unnamed function, taking one int parameter (that it does not use)
and returning int. It also capture its context with reference semantics,
something it also does not make use of.
If you want to use a lambda in conjunction with a function that expects
an int, you need to call the lambda, maybe like this:
class A
{
public:
void f(int a){
_a = a;
}
private:
int _a;
};
class B
{
public:
B()
{
A instance; // = new A(); <- not C++
auto mylambda =
[](int input) -> int
{
int x = 2;
return x;
};
instance.f( mylambda(3) );
}
};

What is the correct way to initialize a variable in C++

I have the following code :
bool c (a == b);
and
bool c {a == b};
where a and b are some variables of same type.
I want to know that, what is the difference in above two initializations and which one should be preferred in what conditions ? Any kind of help will be appreciated.
Both forms are direct initialization.
Using curly braces {} for initialization checks for narrowing conversions and generates an error if such a conversion happens. Unlike (). (gcc issues a warning by default and needs -Werror=narrowing compiler option to generate an error when narrowing occurs.)
Another use of curly braces {} is for uniform initialization: initialize both types with and without constructors using the same syntax, e.g.:
template<class T, class... Args>
T create(Args&&... args) {
T value{std::forward<Args>(args)...}; // <--- uniform initialization + perfect forwarding
return value;
}
struct X { int a, b; };
struct Y { Y(int, int, int); };
int main() {
auto x = create<X>(1, 2); // POD
auto y = create<Y>(1, 2, 3); // A class with a constructor.
auto z = create<int>(1); // built-in type
}
The only drawback of using curly braces {} for initialization is its interaction with auto keyword. auto deduces {} as std::initializer_list, which is a known issue, see "Auto and braced-init-lists".
First one is the C++03 style direct initialization.
The second is C++11 style direct initialization, it additionally checks for narrowing conversions. Herb Sutter recommends the following in new code:
auto c = <expression>;
or when you want to commit to specific type T:
auto c = T{<expression>};
One known drawback with curly braces when T is some class with overloaded constructor, where one constructor gets std::initializer_list as parameter, std::vector for example:
auto v = std::vector<int>{10}; // create vector<int> with one element = 10
auto v = std::vector<int>(10); // create vector<int> with 10 integer elements
Now we have five forms of initializations. They are
T x = expression;
T x = ( expression );
T x ( expression );
T x = { expression };
T x { expression };
Each of the forms has its own peculirities. :)
For example let's assume that you have the following declarations in the global namespace
int x;
void f( int x ) { ::x = x; }
int g() { return x ; }
long h() { return x; }
then in main you can write
int main()
{
int x ( g() );
}
This code will compile successfully.
However a programmer by mistake made a typo
int main()
{
int x; ( g() );
^^
}
Oops! This code also compiles successfully.:)
But if the programmer would write
int main()
{
int x = ( g() );
}
and then make a typo
int main()
{
int x; = ( g() );
^^
}
then in this case the code will not compile.
Well let's assume that the programmer decided at first to set a new value for the global variable x before initializing the local variable.
So he wrote
int main()
{
int x ( f( 10 ), g() );
}
But this code does not compile!
Let's insert equality sign
int main()
{
int x = ( f( 10 ), g() );
}
Now the code compiles successfully!
And what about braces?
Neither this code
int main()
{
int x { f( 10 ), g() };
}
nor this code
int main()
{
int x = { f( 10 ), g() };
}
compiles!:)
Now the programmer decided to use function h(), He wrote
int main()
{
int x ( h() );
}
and his code compiles successfully. But after a time he decided to use braces
int main()
{
int x { h() };
}
Oops! His compiler issues an error
error: non-constant-expression cannot be narrowed from type 'long' to
'int' in initializer list
The program decided to use type specifier auto. He tried two approaches
int main()
{
auto x { 10 };
x = 20;
}
and
int main()
{
auto x = { 10 };
x = 20;
}
and ...some compilers compiled the first program but did not compile the second program and some compilers did not compile the both programs.:)
And what about using decltype?
For example the programmer wrote
int main()
{
int a[] = { 1, 2 };
decltype( auto ) b = a;
}
And his compiler issued an error!
But when the programmer enclosed a in parentheses like this
int main()
{
int a[] = { 1, 2 };
decltype( auto ) b = ( a );
}
the code compiled successfully!:)
Now the programmer decided to learn OOP. He wrote a simple class
struct Int
{
Int( int x = 0 ) : x( x ) {}
int x;
};
int main()
{
Int x = { 10 };
}
and his code compiles successfully.
But the programmer has known that there is function specifier explicit and he has decided to use it
struct Int
{
explicit Int( int x = 0 ) : x( x ) {}
int x;
};
int main()
{
Int x = { 10 };
}
Oops! His compiler issued an error
error: chosen constructor is explicit in copy-initialization
The programmer decided to remove the assignment sign
struct Int
{
explicit Int( int x = 0 ) : x( x ) {}
int x;
};
int main()
{
Int x { 10 };
}
and his code compiled successfully!:)

Initialize and return a struct in one line in C++

I know that you can initialize structs using list syntax:
struct Foo f = {a, b, c};
return f;
Is it possible to do this in one line as you would with classes and constructors?
If you want your struct to remain a POD, use a function that creates it:
Foo make_foo(int a, int b, int c) {
Foo f = { a, b, c };
return f;
}
Foo test() {
return make_foo(1, 2, 3);
}
With C++0x uniform initialization removes the need for that function:
Foo test() {
return Foo{1, 2, 3};
// or just:
return {1, 2, 3};
}
Create a constructor for the struct (just like a class) and just do
return Foo(a,b,c);
Edit: just to clarify: structs in C++ are just like classes with the minor difference that their default access-permission is public (and not private like in a class). Therefore you can create a constructor very simply, like:
struct Foo {
int a;
Foo(int value) : a(value) {}
};

C++: constructor initializer for arrays

I'm having a brain cramp... how do I initialize an array of objects properly in C++?
non-array example:
struct Foo { Foo(int x) { /* ... */ } };
struct Bar {
Foo foo;
Bar() : foo(4) {}
};
array example:
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
// ??? I know the following syntax is wrong, but what's correct?
Baz() : foo[0](4), foo[1](5), foo[2](6) {}
};
edit: Wild & crazy workaround ideas are appreciated, but they won't help me in my case. I'm working on an embedded processor where std::vector and other STL constructs are not available, and the obvious workaround is to make a default constructor and have an explicit init() method that can be called after construction-time, so that I don't have to use initializers at all. (This is one of those cases where I've gotten spoiled by Java's final keyword + flexibility with constructors.)
Edit: see Barry's answer for something more recent, there was no way when I answered but nowadays you are rarely limited to C++98.
There is no way. You need a default constructor for array members and it will be called, afterwards, you can do any initialization you want in the constructor.
Just to update this question for C++11, this is now both possible to do and very natural:
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
Baz() : foo{{4}, {5}, {6}} { }
};
Those braces can also be elided for an even more concise:
struct Baz {
Foo foo[3];
Baz() : foo{4, 5, 6} { }
};
Which can easily be extended to multi-dimensional arrays too:
struct Baz {
Foo foo[3][2];
Baz() : foo{1, 2, 3, 4, 5, 6} { }
};
Right now, you can't use the initializer list for array members. You're stuck doing it the hard way.
class Baz {
Foo foo[3];
Baz() {
foo[0] = Foo(4);
foo[1] = Foo(5);
foo[2] = Foo(6);
}
};
In C++0x you can write:
class Baz {
Foo foo[3];
Baz() : foo({4, 5, 6}) {}
};
Unfortunately there is no way to initialize array members till C++0x.
You could use a std::vector and push_back the Foo instances in the constructor body.
You could give Foo a default constructor (might be private and making Baz a friend).
You could use an array object that is copyable (boost or std::tr1) and initialize from a static array:
#include <boost/array.hpp>
struct Baz {
boost::array<Foo, 3> foo;
static boost::array<Foo, 3> initFoo;
Baz() : foo(initFoo)
{
}
};
boost::array<Foo, 3> Baz::initFoo = { 4, 5, 6 };
You can use C++0x auto keyword together with template specialization on for example a function named boost::make_array() (similar to make_pair()). For the case of where N is either 1 or 2 arguments we can then write variant A as
namespace boost
{
/*! Construct Array from #p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
return boost::array<T,2> ({{ a }});
}
/*! Construct Array from #p a, #p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
return boost::array<T,2> ({{ a, b }});
}
}
and variant B as
namespace boost {
/*! Construct Array from #p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
boost::array<T,1> x;
x[0] = a;
return x;
}
/*! Construct Array from #p a, #p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
boost::array<T,2> x;
x[0] = a;
x[1] = b;
return x;
}
}
GCC-4.6 with -std=gnu++0x and -O3 generates the exact same binary code for
auto x = boost::make_array(1,2);
using both A and B as it does for
boost::array<int, 2> x = {{1,2}};
For user defined types (UDT), though, variant B results in an extra copy constructor, which usually slow things down, and should therefore be avoided.
Note that boost::make_array errors when calling it with explicit char array literals as in the following case
auto x = boost::make_array("a","b");
I believe this is a good thing as const char* literals can be deceptive in their use.
Variadic templates, available in GCC since 4.5, can further be used reduce all template specialization boiler-plate code for each N into a single template definition of boost::make_array() defined as
/*! Construct Array from #p a, #p b. */
template <typename T, typename ... R>
boost::array<T,1+sizeof...(R)> make_array(T a, const R & ... b)
{
return boost::array<T,1+sizeof...(R)>({{ a, b... }});
}
This works pretty much as we expect. The first argument determines boost::array template argument T and all other arguments gets converted into T. For some cases this may undesirable, but I'm not sure how if this is possible to specify using variadic templates.
Perhaps boost::make_array() should go into the Boost Libraries?
This seems to work, but I'm not convinced it's right:
#include <iostream>
struct Foo { int x; Foo(int x): x(x) { } };
struct Baz {
Foo foo[3];
static int bar[3];
// Hmm...
Baz() : foo(bar) {}
};
int Baz::bar[3] = {4, 5, 6};
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
Output:
$ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit
g++ -pedantic arrayinit.cpp -o arrayinit
5
Caveat emptor.
Edit: nope, Comeau rejects it.
Another edit: This is kind of cheating, it just pushes the member-by-member array initialization to a different place. So it still requires Foo to have a default constructor, but if you don't have std::vector then you can implement for yourself the absolute bare minimum you need:
#include <iostream>
struct Foo {
int x;
Foo(int x): x(x) { };
Foo(){}
};
// very stripped-down replacement for vector
struct Three {
Foo data[3];
Three(int d0, int d1, int d2) {
data[0] = d0;
data[1] = d1;
data[2] = d2;
}
Foo &operator[](int idx) { return data[idx]; }
const Foo &operator[](int idx) const { return data[idx]; }
};
struct Baz {
Three foo;
static Three bar;
// construct foo using the copy ctor of Three with bar as parameter.
Baz() : foo(bar) {}
// or get rid of "bar" entirely and do this
Baz(bool) : foo(4,5,6) {}
};
Three Baz::bar(4,5,6);
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
z.foo isn't actually an array, but it looks about as much like one as a vector does. Adding begin() and end() functions to Three is trivial.
Only the default constructor can be called when creating objects in an array.
In the specific case when the array is a data member of the class you can't initialize it in the current version of the language. There's no syntax for that. Either provide a default constructor for array elements or use std::vector.
A standalone array can be initialized with aggregate initializer
Foo foo[3] = { 4, 5, 6 };
but unfortunately there's no corresponding syntax for the constructor initializer list.
There is no array-construction syntax that ca be used in this context, at least not directly. You can accomplish what you're trying to accomplish by something along the lines of:
Bar::Bar()
{
static const int inits [] = {4,5,6};
static const size_t numInits = sizeof(inits)/sizeof(inits[0]);
std::copy(&inits[0],&inits[numInits],foo); // be careful that there are enough slots in foo
}
...but you'll need to give Foo a default constructor.
Ideas from a twisted mind :
class mytwistedclass{
static std::vector<int> initVector;
mytwistedclass()
{
//initialise with initVector[0] and then delete it :-)
}
};
now set this initVector to something u want to before u instantiate an object. Then your objects are initialized with your parameters.
You can do it, but it's not pretty:
#include <iostream>
class A {
int mvalue;
public:
A(int value) : mvalue(value) {}
int value() { return mvalue; }
};
class B {
// TODO: hack that respects alignment of A.. maybe C++14's alignof?
char _hack[sizeof(A[3])];
A* marr;
public:
B() : marr(reinterpret_cast<A*>(_hack)) {
new (&marr[0]) A(5);
new (&marr[1]) A(6);
new (&marr[2]) A(7);
}
A* arr() { return marr; }
};
int main(int argc, char** argv) {
B b;
A* arr = b.arr();
std::cout << arr[0].value() << " " << arr[1].value() << " " << arr[2].value() << "\n";
return 0;
}
If you put this in your code, I hope you have a VERY good reason.
This is my solution for your reference:
struct Foo
{
Foo(){}//used to make compiler happy!
Foo(int x){/*...*/}
};
struct Bar
{
Foo foo[3];
Bar()
{
//initialize foo array here:
for(int i=0;i<3;++i)
{
foo[i]=Foo(4+i);
}
}
};
in visual studio 2012 or above, you can do like this
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
Baz() : foo() { }
};
class C
{
static const int myARRAY[10]; // only declaration !!!
public:
C(){}
}
const int C::myARRAY[10]={0,1,2,3,4,5,6,7,8,9}; // here is definition
int main(void)
{
C myObj;
}