I have something like
struct Foo {
const double a;
const double b;
Foo(double c);
}
Foo::Foo(double c) {
double tmp = f(c);
a = g(tmp);
b = h(tmp);
}
where f,g,h are functions implemented elsewhere. This gives the expected "uninitialized const member" error.
I could fix it with
Foo::Foo(double c): a (g(f(c))), b (h(f(c))) {}
but f is an expensive function and I wouldn't like to run it twice.
My question is, how can I solve this problem without running f twice or making tmp a permanent member of Foo?
Typically, delegating constructors offer a simple solution to this type of problem. In this case you'll have to introduce some way to distinguish between the two constructors:
private:
// the int param is unused
Foo(double fc, int) : a(g(fc)), b(h(fc)) {}
public:
Foo(double c) : Foo(f(c), 0) {}
Related
STRUGGLING WITH C++ CONSTRUCTOR ARGUMENTS
So, I've just came from TS/JS/Py and trying to understand C++ concepts. But I'm struggling with using the parameter of constructor of the class FOR declaring default value for an argument. Here is the code I'm trying to run:
double Phythagorean_Hypotenuse (int& a, int& b ) {
return sqrt((a * a) + (b * b));
};
class Triangle {
public:
int a;
int b;
double c;
Triangle(int a_param, int b_param, double c_param = Phythagorean_Hypotenuse(a_param, b_param)) {
a = a_param;
b = b_param;
c = c_param;
}
};
and inside of the main function
Triangle mytri_1(10, 20);
std::cout << mytri_1.a << std:endl;
But when I try to run this code, IDE is throwing me some errors like
[Error] 'a_param' was not declared in this scope
or
[Error] call to 'Triangle::Triangle(int, int, double)' uses the default argument for parameter 3, which is not yet defined
So, please, can someone who can fix this answer the question?
Thanks.
There are some issues that prevent your code from compiling, namely:
Constructors do not have return type.
double c_param = Phythagorean_Hypotenuse(a_param, b_param) is not valid for a parameter, a_param, b_param will not be recognized.
Recommend change:
Since the result of a hypothenuse calculation will most likely be a decimal value, c should be a double.
You can do something like this:
Running sample
#include <iostream>
#include <cmath>
double Phythagorean_Hypotenuse (int& a, int& b ) {
return sqrt((a * a) + (b * b));
};
class Triangle {
public:
int a;
int b;
double c; //should be double
//initializer list is a good practice for member initialization
Triangle(int a_param, int b_param)
: a(a_param), b(b_param), c(Phythagorean_Hypotenuse(a, b)) {}
};
int main(){
Triangle mytri_1(10, 20);
std::cout << mytri_1.a << std::endl;
std::cout << mytri_1.b << std::endl;
std::cout << mytri_1.c << std::endl;
}
Output:
10
20
22.3607
As the compiler is pointing out, the other constructor arguments are not available as default parameters for the c_param argument. Rather than using default values, just overload the constructor, including one that just accepts 2 parameters. This constructor can then invoke the other constructor that accepts all 3:
// Constructor overload that accepts all 3 parameters
Triangle(int a_param, int b_param, double c_param):
a(a_param), b(b_param), c(c_param) {
}
// Constructor overload that accepts just a and b, call the other constructor
// to set all 3 members
Triangle(int a_param, int b_param):
Triangle(a_param, b_param, Phythagorean_Hypotenuse(a_param, b_param)) {
}
Default parameter values cannot reference other parameters. You can define two overloads, one of which delegates to the other, to do what you want:
class Triangle {
public:
double a;
double b;
double c;
Triangle(double a_param, double b_param, double c_param)
: a{a_param},
b{b_param},
c{c_param}
{}
Triangle(double a_param, double b_param)
: Triangle{a_param, b_param, Phythagorean_Hypotenuse(a_param, b_param)}
{}
};
Live Demo
A few other notes:
Class constructors do not have a return type. I changed void Triangle(...) to Triangle(...)
I used constructor initialization lists instead of assignment in the constructor's body. There's likely no difference for small primitive values like ints or doubles, but it's a good habit to get into and can make a big difference for more complex types
int doesn't make sense for the type of c (or a or b for that matter). The sides of a triangle are unlikely to all be integers
There's no reason to pass parameters to Pythagorean_Hypotenuse by reference. It's simpler and likely faster to pass them by value
Why are default arguments in C++ trailing ones?
if you had void func(int a = 0, int b);, how would you specify to use the default parameter in calling this function?
Because that is how the language has been designed.
A more interesting question would be: what are the alternatives?
Suppose you have void f(A a = MyA, B b);
Placeholder / blank argument: f(_, abee) or f(, abee)
Named arguments (like in Python): f(b = abee)
But those are niceties and certainly not necessary, because unlike Python C++ supports function overloading:
void f(A a, B b);
void f(B b) { f(MyA, b); }
and thus the default arguments are unnecessary... especially considering that there are issues when used with polymorphic code because default arguments are statically resolved (compile-time).
struct Base
{
virtual void func(int g = 3);
};
struct Derived
{
virtual void func(int g = 4);
};
int main(int argc, char* argv[])
{
Derived d;
d.func(); // Derived::func invoked with g == 4
Base& b = d;
b.func(); // Derived::func invoked with g == 3 (AH !!)
}
Regarding named parameters:
The feature can be emulated using function objects.
class Func
{
public:
Func(B b): mA(MyA), mB(b) {}
A& a(A a) { mA = a; }
B& b(B b) { mB = b; }
void operator()() { func(mA, mB); }
private:
A mA;
B mB;
};
int main(int argc, char* argv[])
{
A a;
B b;
Func(b)();
Func(b).a(a)();
}
In case you don't want to copy the arguments, you have the possibility to use references/pointers though it can get complicated.
It's a handy idiom when you have a whole lot of defaults with no real order of priority.
Just to supplement #tenfour's answer. C++ FAQ Lite has a topic describing named parameters and I think the topic addresses your issue to some extent.
Because in a function call you have to call the non-default arguments in any case. If you put your default argument at the beginning of the argument list, how are you supposed to say you are setting the default argument or the other ones?
This question already has answers here:
How do you pass a member function pointer?
(6 answers)
Closed 9 years ago.
I have a class
class A{
A(/*constructor arguments*/);
double MethA(double);
};
And I want to pass the method MethA in a function that takes a pointer to a function :
double function(double (*f)(double), double x){
return f(x);
}
So what I'm doing is to call
A a(/*constructor arguments*/);
function(a.MethA,1.0);
but it doesn't compile.
I'm pretty sure that this question is answered somewhere else, but I couldn't find where because I'm not sure that the terminology I use is correct. Am I trying to pass a pointer on a class method as a function argument ? Or, to pass a function pointer as a member of a class... I'm confused :-(
When you need to use a pointer to member function, you need to pass two separate things:
what member function to call and
what instance to call it on.
In C++, you can't combine them in one construct, like you want to:
A a;
bar(a.foo);
is not valid C++.
Instead, you have to do this:
A a;
bar(a, &A::foo)
And declare and implement bar() accordingly:
void bar(A &a, void (A::*method)()) {
a.*method();
}
See Arkadiy's answer if you want to see how to properly use member function pointers.
BUT
As requested in the comments: if the compiler you are using supports lambdas (some without full C++11 do). You can do something like the following, which looks more like the syntax you are attempting to use.
Your definition for function changes to something like:
template <typename F>
double function(F f, double x){
return f(x);
};
a function template that accepts a parameter that is callable with a double.
At your call-site you do this:
A a(/*constructor arguments*/);
function([&](double x){return a.MethA(x);},1.0);
That generates a function object in-place that is bound to your class instance a by reference.
The template can be made fully typesafe with some magic in <type_traits>, but as-is it will give you template spew if you pass something very wrong.
It has to be a static function!
#include <iostream>
#include <cassert>
class A {
public:
static double MethA(double x) { return 5 * x; }
};
typedef double (*ftype)(double);
double function(ftype f) {
assert(f != NULL);
return f(7);
}
int main(int, char**) {
// expect "35\n" on stdout
std::cout << function(A::MethA) << "\n";
}
It has to be static because you can't access any of A's variables without knowing which A object are you refering to! If you need A's non-static member variables, you need to pass a reference to an a into the static function:
#include <iostream>
#include <cassert>
class A {
double fX;
public:
A(double x) : fX(x) { }
double methB(double x) const { return fX * x; }
static double MethB(double x, const A& a) {
return a.methB(x);
}
};
typedef double (*ftype2)(double, const A&);
double function_with_context(ftype2 f, const A& a) {
assert(f != NULL);
return f(7, a);
}
int main(int, char**) {
A a(6);
// expect "42\n" on stdout
std::cout << function_with_context(A::MethB, a) << "\n";
}
But it's sometimes better to use inheritance and polymorphism to achieve this sort of interface:
#include <iostream>
class MyInterface {
public:
virtual double f(double x) const = 0;
};
class A : public MyInterface {
double fX;
public:
A(double x) : fX(x) { }
double f(double x) const {
return fX * x;
}
};
double function(const MyInterface& o) {
return o.f(7);
}
int main(int, char**) {
A a(6);
// expect "42\n" on stdout
std::cout << function(a) << "\n";
}
How should I write a constructor for a class to initialize a member that is a const structure / has const fields?
In the following example, I define a constructor within structure B and it works fine to initialize it's const fields.
But when I try to use the same technique to initialize const fields of structure C within class A it doesn't work. Can someone please help me and rewrite my class A in a way, that it starts working?
#include <iostream>
class A
{
public:
struct C
{
C (const int _x) : x (_x) {}
const int x;
};
C c (3);
};
int main (int argc, char *argv[])
{
struct B
{
B (const int _x) : x (_x) {}
const int x;
};
B b (2);
std::cout << b.x << std::endl;
A a;
std::cout << a.c.x << std::endl;
return 0;
}
P.S.
I did some search and I think, I understand, that unless I have C++11 support or want to use boost library, I have to define a helper function to initialize a const struct within initialization list
(C++ Constant structure member initialization)
but it seems to be crazy that I have to define alike struct, but with non const fields to initialize a struct with const fields, doesn't it?
Another thing that I found tells that I should initialize const members in a constructor of the class A, rather than in a constructor of the struct C (C++ compile time error: expected identifier before numeric constant) but it also seems crazy to me, because why should I rewrite a class constructor every time I want to add a new struct, isn't it more convenient to have a separate constructor for each struct C within the class A?
I would be grateful to any comments that could possibly clarify my confusion.
I'd do the job like this:
#include <iostream>
class A {
public:
struct C {
C(const int _x) : x(_x) {}
const int x;
};
C c; // (3);
A() : c(3) {}
};
int main(int argc, char *argv []) {
A a;
std::cout << a.c.x << std::endl;
return 0;
}
Note that it's not a matter of using a ctor in A or in C, but of the ctor for A telling how the ctor for C should be invoked. If the value that will be passed will always be 3 that's not necessary, but I'm assuming you want to be a able to pass a value of your choice when you create the C object, and it will remain constant after that.
If the value will always be the same (3 in this case) you can simplify things a lot by also making the constant static:
struct A {
struct C {
static const int x = 3;
};
C c;
};
int main() {
A a;
std::cout << a.c.x << "\n";
}
So, if the value is identical for all instances of that class, make it static const, initialize it in place, and life is good. If the value is not known until you create an instance of the object, and remains constant thereafter for the life of that object, you need to pass it in through the constructors.
For a slightly different case, there's a third possibility: if C is an independent class (not nested inside of A) you might have a situation where other instances of C use various values, but all instances of C inside an A always use the same value. In this case, you'd do something like:
struct C {
const int x;
C(int x) : x(x) {}
};
struct A {
C c;
A() : c(3) {}
};
Of course, you can do the same thing when C is nested inside of A, but when/if you do, it generally means you're setting the same value for all instances of C, so you might as well use the static const approach instead. The obvious exception would be if A had multiple constructors, so (for example) A's default constructor passed one value for C::x and its copy constructor passed a different value.
Why are default arguments in C++ trailing ones?
if you had void func(int a = 0, int b);, how would you specify to use the default parameter in calling this function?
Because that is how the language has been designed.
A more interesting question would be: what are the alternatives?
Suppose you have void f(A a = MyA, B b);
Placeholder / blank argument: f(_, abee) or f(, abee)
Named arguments (like in Python): f(b = abee)
But those are niceties and certainly not necessary, because unlike Python C++ supports function overloading:
void f(A a, B b);
void f(B b) { f(MyA, b); }
and thus the default arguments are unnecessary... especially considering that there are issues when used with polymorphic code because default arguments are statically resolved (compile-time).
struct Base
{
virtual void func(int g = 3);
};
struct Derived
{
virtual void func(int g = 4);
};
int main(int argc, char* argv[])
{
Derived d;
d.func(); // Derived::func invoked with g == 4
Base& b = d;
b.func(); // Derived::func invoked with g == 3 (AH !!)
}
Regarding named parameters:
The feature can be emulated using function objects.
class Func
{
public:
Func(B b): mA(MyA), mB(b) {}
A& a(A a) { mA = a; }
B& b(B b) { mB = b; }
void operator()() { func(mA, mB); }
private:
A mA;
B mB;
};
int main(int argc, char* argv[])
{
A a;
B b;
Func(b)();
Func(b).a(a)();
}
In case you don't want to copy the arguments, you have the possibility to use references/pointers though it can get complicated.
It's a handy idiom when you have a whole lot of defaults with no real order of priority.
Just to supplement #tenfour's answer. C++ FAQ Lite has a topic describing named parameters and I think the topic addresses your issue to some extent.
Because in a function call you have to call the non-default arguments in any case. If you put your default argument at the beginning of the argument list, how are you supposed to say you are setting the default argument or the other ones?