do_decimal_point and do_thousands_sep seem to be completely ignored by my stream.
What I want is to do is use a period for my thousands_sep and a comma for my decimal_point in get_money. So I override moneypunct but it is just ignored :(
struct punct_facet : public moneypunct<char> {
char_type do_decimal_point() const { return ','; }
char_type do_thousands_sep() const { return '.'; }
};
int main()
{
istringstream USCurrency("1,234.56 -1,234.56 1.234,56 -1.234,56");
USCurrency.imbue(locale(locale("en-US"), new punct_facet));
int index = 0;
long double value;
do{
value = 0.0;
USCurrency >> get_money(value, true);
cout << ++index << ": " << value << endl;
} while (value == 123456.0 || value == -123456.0);
return 0;
}
I would expect this to just output:
1: 123
But instead I get:
1: 123456
2: -123456
3: 123
What am I doing wrong? I'm using Visual Studio 2013, in case that may be obvious from the "en-US".
EDIT:
I've discovered when I place a break-point in do_decimal_point or do_thousands_sep that it is never hit. I'm not sure why not, but that information seems to be relevant to the problem.
This solution is really just an explanation of the answer given here.
Both the copy constructor and assignment opperator are deleted by the moneypunct implementation. Which leaves two bad options for constructing punct_facet:
Duplicate all moneypunct members in punct_facet and call all moneypunct virtual functions in the punct_facet constructor to initialize them. This has the obvious drawback of a punct_facet object being twice as fat as it should be and it's constructor running longer than is strictly necessary.
Use pointers and a compiler specific knowledge of object layout to effect a copy construction from a moneypunct to a punct_facet. This has the obvious drawback of not being cross-platform and intentionally disregarding the standard implementation's design.
For this answer I have elected bad option 2, because the implementation of moneypunct is already compiler specific for any construction argument other than: "", "C", or "POSIX" and because there is an open bug against the deleted moneypunct copy constructor and assignment operator. (Incidentally if the moneypunct construction argument is adjusted option 2 works in gcc 5.1.0 as well, but it will not work in Clang 3.6.0.) Hopefully Microsoft will provide a more functional workaround for that bug soon and we won't have to use either bad option.
So if punct_facet is implemented like this:
template <typename T>
class punct_facet : public T {
private:
void Init(const T* money){
const auto vTablePtrSize = sizeof(void*);
memcpy(reinterpret_cast<char*>(this) + vTablePtrSize, reinterpret_cast<const char*>(money) + vTablePtrSize, sizeof(T) - vTablePtrSize);
}
protected:
typename T::char_type do_decimal_point() const {
return typename T::char_type(',');
}
typename T::char_type do_thousands_sep() const {
return typename T::char_type('.');
}
public:
punct_facet(){
Init(&use_facet<T>(cout.getloc()));
}
punct_facet(const T* money){
Init(money);
}
};
You can construct with either of the punct_facet constructors and you will get your expected output:
123
To use the default constructor you'd need to add cout.imdue(locale("en-US")); at the top of main and change your imdue statement to:
USCurrency.imbue(locale(locale("en-US"), new punct_facet<moneypunct<char, true>>()));
To use the custom constructor you'd only need to change your imdue statement to:
USCurrency.imbue(locale(locale("en-US"), new punct_facet<moneypunct<char, true>>(&use_facet<moneypunct<char, true>>(locale("en-US")))));
The default constructor is preferable as a discrepancy between your template type and your constructor argument could result in some bad behavior.
One minor note, your USCurrency is not using international currency format, so there's no need to use moneypunct<char, true>, moneypunct<char> will work just fine. Just remember to change it everywhere as a discrepancy between the template arguments to punct_facet and the arguments used in get_money will again result in the unexpected behavior you were seeing.
Related
Sometimes for algebraic types it is convenient to have a constructor that takes a literal value 0 to denote the neutral element, or 1 to denote the multiplicative identity element, even if the underlying type is not an integer.
The problem is that it is not obvious how to convince the compiler only to accept, 0 or 1 without accepting any other integer.
Is there a way to do this in C++14 or beyond, for example combining literals, constexpr or static_assert?
Let me illustrate with a free function (although the idea is to use the technique for a constructor that take a single argument. Contructors cannot take template parameters either).
A function that accepts zero only could be written in this way:
constexpr void f_zero(int zero){assert(zero==0); ...}
The problem is that, this could only fail at runtime. I could write f_zero(2) or even f_zero(2.2) and the program will still compile.
The second case is easy to remove, by using enable_if for example
template<class Int, typename = std::enable_if_t<std::is_same<Int, int>{}> >
constexpr void g_zero(Int zero){assert(zero==0);}
This still has the problem that I can pass any integer (and it only fails in debug mode).
In C++ pre 11 one had the ability to do this trick to only accept a literal zero.
struct zero_tag_{};
using zero_t = zero_tag_***;
constexpr void h_zero(zero_t zero){assert(zero==nullptr);}
This actually allowed one to be 99% there, except for very ugly error messages.
Because, basically (modulo Maquevelian use), the only argument accepted would be h_zero(0).
This is situation of affairs is illustrated here https://godbolt.org/z/wSD9ri .
I saw this technique being used in the Boost.Units library.
1) Can one do better now using new features of C++?
The reason I ask is because with the literal 1 the above technique fails completely.
2) Is there an equivalent trick that can be applied to the literal 1 case? (ideally as a separate function).
I could imagine that one can invent a non-standard long long literal _c that creates an instance of std::integral_constant<int, 0> or std::integral_constant<int, 1> and then make the function take these types. However the resulting syntax will be worst for the 0 case. Perhaps there is something simpler.
f(0_c);
f(1_c);
EDIT: I should have mentioned that since f(0) and f(1) are potentially completely separate functions then ideally they should call different functions (or overloads).
In C++20 you can use the consteval keyword to force compile time evaluation. With that you could create a struct, which has a consteval constructor and use that as an argument to a function. Like this:
struct S
{
private:
int x;
public:
S() = delete;
consteval S(int _x)
: x(_x)
{
if (x != 0 && x != 1)
{
// this will trigger a compile error,
// because the allocation is never deleted
// static_assert(_x == 0 || _x == 1); didn't work...
new int{0};
}
}
int get_x() const noexcept
{
return x;
}
};
void func(S s)
{
// use s.get_x() to decide control flow
}
int main()
{
func(0); // this works
func(1); // this also works
func(2); // this is a compile error
}
Here's a godbolt example as well.
Edit:
Apperently clang 10 does not give an error as seen here, but clang (trunk) on godbolt does.
You can get this by passing the 0 or 1 as a template argument like so:
template <int value, typename = std::enable_if_t<value == 0 | value == 1>>
void f() {
// Do something with value
}
The function would then be called like: f<0>(). I don't believe the same thing can be done for constructors (because you can't explicitly set template parameters for constructors), but you could make the constructor(s) private and have static wrapper functions which can be given template parameters perform the check:
class A {
private:
A(int value) { ... }
public:
template <int value, typename = std::enable_if_t<value == 0 || value == 1>>
static A make_A() {
return A(value);
}
};
Objects of type A would be created with A::make_A<0>().
Well... you have tagged C++17, so you can use if constexpr.
So you can define a literal type when 0_x is a std::integral_constant<int, 0> value, when 1_x is a std::integral_constant<int, 1> and when 2_x (and other values) gives a compilation error.
By example
template <char ... Chs>
auto operator "" _x()
{
using t0 = std::integer_sequence<char, '0'>;
using t1 = std::integer_sequence<char, '1'>;
using tx = std::integer_sequence<char, Chs...>;
if constexpr ( std::is_same_v<t0, tx> )
return std::integral_constant<int, 0>{};
else if constexpr ( std::is_same_v<t1, tx> )
return std::integral_constant<int, 1>{};
}
int main ()
{
auto x0 = 0_x;
auto x1 = 1_x;
//auto x2 = 2_x; // compilation error
static_assert( std::is_same_v<decltype(x0),
std::integral_constant<int, 0>> );
static_assert( std::is_same_v<decltype(x1),
std::integral_constant<int, 1>> );
}
Now your f() function can be
template <int X, std::enable_if_t<(X == 0) || (X == 1), bool> = true>
void f (std::integral_constant<int, X> const &)
{
// do something with X
}
and you can call it as follows
f(0_x);
f(1_x);
For the case of Ada, you can define a subtype, a new type, or a derived type that is constrained only for the values of Integer 0 and 1.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure two_value is
-- You can use any one of the following 3 declarations. Just comment out other two.
--subtype zero_or_one is Integer range 0 .. 1; -- subtype of Integer.
--type zero_or_one is range 0 .. 1; -- new type.
type zero_or_one is new Integer range 0 .. 1; -- derived type from Integer.
function get_val (val_1 : in zero_or_one) return Integer;
function get_val (val_1 : in zero_or_one) return Integer is
begin
if (val_1 = 0) then
return 0;
else
return 1;
end if;
end get_val;
begin
Put_Line("Demonstrate the use of only two values");
Put_Line(Integer'Image(get_val(0)));
Put_Line(Integer'Image(get_val(1)));
Put_Line(Integer'Image(get_val(2)));
end two_value;
upon compiling you get the following warning message, although compiles successfully :
>gnatmake two_value.adb
gcc -c two_value.adb
two_value.adb:29:40: warning: value not in range of type "zero_or_one" defined at line 8
two_value.adb:29:40: warning: "Constraint_Error" will be raised at run time
gnatbind -x two_value.ali
gnatlink two_value.ali
And executing it gives the runtime error as specified by the compiler
>two_value.exe
Demonstrate the use of only two values
0
1
raised CONSTRAINT_ERROR : two_value.adb:29 range check failed
So, basically you can constrain the values by defining the new types, derived types or subtypes, you don't need to include the code to check the range, but based on your data type the compiler will automatically warn you.
This isn't a modern solution, but adding on to Zach Peltzer's solution, you can keep your syntax if you use macros...
template <int value, typename = std::enable_if_t<value == 0 | value == 1>>
constexpr int f_impl() {
// Do something with value
return 1;
}
#define f(x) f_impl<x>()
int main() {
f(0); //ok
f(1); //ok
f(2); //compile time error
}
Though, with the constructor problem you could just make the class templated instead of trying to have a templated constructor
template<int value, typename = std::enable_if_t<value == 0 | value == 1>>
class A {
public:
A() {
//do stuff
}
};
int main() {
A<0> a0;
auto a1 = A<1>();
// auto a2 = A<2>(); //fails!
}
The best solution to accept literal 0 that I've found to date is to use std::nullptr_t as the function's input:
struct math_object
{
real x,y,z;
math_object(std::nullptr_t) : x(0), y(0), z(0) {}
};
This has conversion advantages over some of the other solutions. For example, it allows syntax such as.. void MyFunc(const math_object &obj=0); I've been using this for years, and haven't found any trouble. However, I do not have a similar solution for literal 1. For that, I created a construct::id structure that has a global IDENTITY variable.
There's a basic problem. How can you do that in the compiler to be done for a parameter, and at the same time be efficient? Well, what do you need exactly?
That is included in strong typed languages like Pascal, or Ada. The enumerated types have only a couple of values, and the types are normally checked at development, but otherwise, the checks are eliminated by some compiler option at runtime, because just everything goes well.
A function interface is a contract. It is a contract between a seller (the writer of the function) and a buyer (the user of that function). There's even an arbiter, which is the programming language, that can act upon if someone tries to cheat the contract. But at the end, the program is being run in a machine that's open to make arbitraryness like modifying the set of enumerated values and put in the place a completely (and not permitted value).
The problem comes also with separate compilation. Separate compilation has its drawbacks, as it must face a compilation, without having to recheck and retest all previous compilations you have made. Once a compilation is finished, everything you have put in the code is there. If you want the code to be efficient, then the tests are superfluous, because caller and implementer both cope with the contract, but if you want to catch a lyer, then you have to include the test code. And then, it is better to do once for all cases, or is it better to let the programmer decide when and when not we want to catch a lyer?
The problem with C (and by legacy with C++) is that they were inspired by very good programmers, that didn't mistakes, and that have to run their software in big and slow machines. They decided to make both languages (the second was for interoperability purposes) weak typed... and so they are. Have you tried to program in Ada? or Modula-2? You'll see that, over the time, the strong typing thing is more academic than otherwise, and finally what you want, as a professional, is to have the freedom to say: now I want to be safe (and include test code), and now I know what I'm doing (and please be most efficient as you can)
Conclusion
The conclussion is that you are free to select the language, to select the compiler, and to relax the rules. The compilers have the possibility to allow you that. And you have to cope with it, or invent (this is something that todays happens almost each week) your own programming language.
This is the answer to my question, based on #IlCapitano answer for a wrapper class.
This wrapper class can be made private an used only on the construction.
class Matrix {
struct ZeroOROne {
/*implicit*/ consteval ZeroOROne(int n) : val_{n} {
if (n != 0 and n != 1) {throw;} // throw can produce an error at compile time
}
int val_;
};
public:
constexpr Matrix(ZeroOROne _0_or_1) {
if(_0_or_1.val_ == 0) { // this cannot be if constexpr, but that is ok
a00 = a01 = a10 = a11 = 0.0;
new int{0}; // allocation could is ok here
} else {
a00 = a11 = 1.0;
a10 = a01 = 0.0;
new int{0}; // allocation could is ok here
}
}
double a00; double a01;
double a10; double a11;
};
In this way, only Matrix A(0) or Matrix A(1) are allowed.
(Although it works with constant variables as well, but that is ok.)
int main() {
// ZeroOROne(0);
// ZeroOROne(1);
// ZeroOROne(2); // compilation error
Matrix A(0);
Matrix B(1);
// Matrix C(2); // compilation error
int const d = 0; // this works because the compiler can "see" the 0.
Matrix D(d);
constexpr int e = 0;
Matrix E(e);
// int f = 0;
// Matrix F(f); // compile error
return B.a00;
}
Here it is shown that the "runtime" if in the constructor is not a problem and can be elided by the compiler: https://godbolt.org/z/hd6TWY6qW
The solution needs C++20 and it works in recent version of GCC and clang.
This is certainly related to a bunch of other questions which have been answered, but I have been unable to derive the answer for my specific case from them, largely because I'm not actually a programmer; I'm just an engineer who happens to have to write some code.
Here's the situation:
I have a bunch of variables I'd like to collect together, probably into a structure.
All but two I would like to initialize to zero; two specific variables (which don't happen to be the first two) need to be initialized to one.
The actual names are unique and meaningful enough that using a vector wouldn't be appropriate, plus there are some doubles in there too. I'm keeping my example below simple for clarity.
Because of the project I'm working on, I'm stuck with C++98, so even if C++11 has more elegant solutions, they won't work for me.
I am thinking something along these lines for the structure itself:
struct allFlags
{
int flagAA;
int flagAB;
int flagAC;
int flagAD;
int flagAE;
// ...
// there's about 100 variables total
// ...
int flagZZ;
};
I want to have all the flags initialized to 0 except for flagAD and flagAE, which should be 1.
So first of all, I am not sure if I should use typedef struct allFlags or struct allFlags. Next, I am not sure if I should be creating a constructor (which I think only would apply in the case of no typedef?) or making the defaults happens when I instantiate the structure. I have seen things like this (which would be put inside the struct definition):
allFlags() : flagAD(1), flagAE(1) { /*not sure of I'd need anything here*/ }
but I wouldn't want to have to list out all other ~98 variables by name individually in the constructor body to set them to zero. I have also seen things using memset which could potentially help, but I'm not sure the best way to do it.
And finally one additional related question is how to actually declare an instance of my structure (which results in the initial values I want). It looks like sometimes a struct is instantiated with the new keyword and sometimes is it treated more like a base data type, i.e. I have seen both of these in searching:
allFlags flagset1;
flagset2 = new allFlags;
I have also seen syntax which would be like this rather than using a constructor at all:
allFlags flagset3 = {}; // to zero all fields first
flagset3.flagAD = 1;
flagset3.flagAE = 1;
but I'd rather keep the instantiation as clean and simple as possible.
Please forgive the question. I have tried to do my homework before asking, but my C++ knowledge is mediocre at best and so some of the seemingly relevant answers I've found I either didn't fully understand or just raised more questions.
If you feel comfortable with using templates, you can use a class template to automate clean initialization of all member variables of allFlags.
// class template to help initialize members cleanly.
template <typename T>
struct flag
{
// Constructors
flag() : val(0) {}
flag(T const& v) : val(v) {}
// Automatic cast operators to T
operator T& () { return val; }
operator T const& () const { return val; }
// Comparison operators
bool operator==(flag const& rhs) const { return val == rhs.val; }
bool operator!=(flag const& rhs) const { return val != rhs.val; }
bool operator<(flag const& rhs) const { return val < rhs.val; }
T val;
};
typedef flag<int> IntFlag;
typedef flag<double> DoubleFlag;
struct allFlags
{
// Initialize all flags bug flagAD to zero.
allFlags() : flagAD(1) {}
IntFlag flagAA;
IntFlag flagAB;
IntFlag flagAC;
IntFlag flagAD;
IntFlag flagAE;
IntFlag flagZZ;
};
#include <iostream>
int main()
{
allFlags f;
std::cout << f.flagAA << " " << f.flagAD << std::endl;
}
Output:
0 1
You answered your own question quite well:
allFlags flagset3 = {}; // to zero all fields first
flagset3.flagAD = 1;
flagset3.flagAE = 1;
It is clean, and very clear about your intentions. Later, when someone else has to read your code they will understand exactly what you are trying to do.
It is similar to what you see in device driver programming:
registerX = 0 | 1 << BIT2 | 1 << BIT3;
In C++11, what is the best way to provide two versions of a method, one to modify the object itself and one to return a modified copy?
For example, consider a string class which has the "append(string)" method. Sometimes you might want to use append to modify your existing string object, sometimes you might want to keep your string object the same and create a copy.
Of course, I could just implement the first version and manually create a new object everytime I need one but that adds multiple temporary variables and lines of code to my project.
If it is still not clear what I am trying to do:
String s1("xy");
String s2 = s1.appendCopy("z");
s1.appendThis("w");
// s1 == "xyw"
// s2 == "xyz"
In Ruby there is a concept (or rather, a naming convention) which says for such methods, there are two variants: append (creates a new String) and append! (modifies this object)
C++ does not have something like this, so I would be stuck with ugly method names like "appendCopy".
Is there a good way to implement what I am trying to do?
So far, the best idea I had would be to make the modifying versions class members and the copying/immutable versions static methods which take the object to work on as a const argument.
There is actually a guideline, expressed by Herb Sutter in GotW #84:
Prefer non-member non-friend functions.
In your specific case, append (in-place) requires modifying the existing string so is well-suited to be a class-method, while append (copying) does not, so (following the guideline) should not be a class-method.
Thus:
void std::string::append(std::string const&);
inline std::string append(std::string left, std::string const& right) {
left.append(right);
return left;
}
After popular request, here are two overloads that can be used to optimize performance. First the member-version that may reuse its argument's buffer:
void std::string::append(std::string&& other) {
size_t const result_size = this->size() + other.size();
if (this->capacity() < result_size) {
if (other.capacity() >= result_size) {
swap(*this, other);
this->prepend(other);
return;
}
// grow buffer
}
// append
}
And second the free-function that may reuse its right-hand buffer:
inline std::string append(std::string const& left, std::string&& right) {
right.prepend(left);
return right;
}
Note: I am not exactly sure there are not ambiguous overloads manifesting. I believe there should not be...
With the new move semantics you can write:
class A{
public:
// this will get the property
const dataType& PropertyName() const { return m_Property; }
// this wil set the property
dataType& PropertyName() { return m_Propery; }
private:
dataType m_Propery;
};
main()
{
A a;
a.PropertyName() = someValueOfType_dataType; // set
someOtherValueOfType_dataType = a.PropertyName(); // get
}
I'm trying to create a small set of classes implementing a "safe flag" pattern, which would allow only predefined values to be OR-ed together. I've came up with something like that:
class MyClass;
class CreateFlag
{
friend class MyClass;
private:
int value;
CreateFlag(int newValue)
{
value = newValue;
}
public:
CreateFlag operator | (const CreateFlag & right) const
{
int newValue = value | right.value;
return CreateFlag(newValue);
}
CreateFlag(const CreateFlag && flag)
{
value = flag.value;
}
CreateFlag(const CreateFlag & flag)
{
value = flag.value;
}
static const CreateFlag Flag1;
static const CreateFlag Flag2;
static const CreateFlag Flag4;
};
const CreateFlag CreateFlag::Flag1 = CreateFlag(1);
const CreateFlag CreateFlag::Flag2 = CreateFlag(2);
const CreateFlag CreateFlag::Flag4 = CreateFlag(4);
class MyClass
{
public:
static void DisplayFlag(CreateFlag flag)
{
printf("Flag value: %d\n", flag.value);
}
};
int main(int argc, char * argv)
{
MyClass::DisplayFlag(CreateFlag::Flag1 | CreateFlag::Flag2);
getchar();
}
The problem is, that CreateFlag has a private ctor (what is intentional), so there is no way to specify the values of CreateFlag's static fields and the above code does not compile.
A way to bypass this restriction is to change static fields into static methods returning an instance of CreateFlag, but that's a dirty solution, as you would have to call the metod like:
MyClass::DisplayFlag(CreateFlag::Flag1() | CreateFlag::Flag2());
Is there a direct solution? If it changes anything, the flag definitions may be as well moved to the MyClass class.
I know also, that C++11 supports in-place initialization of static fields, but unfortunatelly VC++10 doesn't support this construct yet...
Edit I've modified the code, such that anyone can copy it and use, it compiles now and works as intended to.
The above code doesn't compile, but I think that it's not compiling for reasons beyond what you're expecting. Specifically, the compile error is in this line:
MyClass::DisplayFlag(CreateFlag::Flag1 | CreateFlag::Flag2);
The reason is that DisplayFlag takes its CreateFlag argument by value, and you've marked the copy constructor private.
If you're trying to ensure that people can't OR together invalid values, I don't think you need the copy constructor to be private. Making copies of CreateFlags that you know are valid doesn't allow clients to do anything that they previously couldn't do. If you omit the definition of the copy constructor and just let C++'s default copy support work for you, you should be just fine.
The lines that you've indicated as causing the error don't seem to cause any problems. It compiles just fine once you remove the copy constructor.
Hope this helps!
I am learning c++, and I just got to the object oriented chapter. I have a question about creating objects inside if statements.
The problem I'm working on says to create a class that will display a report header. The class has a default constructor that sets the company name and report name to a generic thing, and also, if the user wants, has a constructor that takes two arguments (strings company name and report name).
The problem says, specifically, "A two-parameter default constructor should allow these [company and report names] to be specified at the time a new Report object is created. If the user creates a Report object without passing any arguments, use the default values. Otherwise, use user specified values for the names."
So my question is, how to create these objects? I understand how to create an object without any arguments (i.e. Report newobj;), and also with arguments (i.e. Report newobj(string string);). Basically, I get how to create these objects initially at the top of my main function. But is it possible to create them inside if statements based on user choices? Here is what I have so far and, obviously, it doesn't work:
#include <iostream>
#include <string>
#include "report.h"
using namespace std;
bool enter_company_name(); // return true if user wants to enter company name
bool print_form(); // return true if user wants to print in formatted output
int main()
{
string company_name,
report_name;
bool name = false,
format = false;
name = enter_company_name();
format = print_form();
if (name)
{
cout << "Enter company name: ";
getline(cin, company_name);
cout << "Enter report name: ";
getline(cin, report_name);
Report header(company_name, report_name); // THIS IS MY PROBLEM
}
else
Report header; // THIS IS MY PROBLEM
if (format)
header.print_formatted();
else
header.print_one_line();
return 0;
}
bool enter_company_name()
{
char choice;
cout << "Do you want to enter a name?\n>";
cin >> choice;
if (choice == 'y' || choice == 'Y')
return true;
else
return false;
}
bool print_form()
{
char choice;
cout << "Do you want to print a formatted header?\n>";
cin >> choice;
if (choice == 'y' || choice == 'Y')
return true;
else
return false;
}
So I want to create an object using default values if none are specified, or create one with the user values if that's the choice given. I just can't figure out how to do it interactively in c++. I have not been able to find any similar questions anywhere so far.
The closest thing I've come across uses pointers to do something similar to what I want to do, but the book I'm using has not gotten to pointers yet, and I want to try to figure out a way to do it that stays within the bounds of the chapter I'm working in (i.e. not using pointers).
I didn't include the header file or class implementation file because I don't think they are relevant here.
Thank you in advance!
First off, you cannot create an object within a conditional statement and use it after the conditional statement: the two branches of the conditional statement create a scope each and any object created within in destroyed a the end of the branch. That is, you need to come up with a different approach. The simplest approach is probably to delegate the creation of the object to a function which returns the objects as appropriate:
Report makeReport() {
if (enter_company_name()) {
...
return Report(name, company);
}
return Report();
}
...
Report report = makeReport();
An alternative approach is to use the ternary operator to conditonally create the Report one way or another:
bool get_company_name = enter_company_name();
std::string name(get_company_name? read_name(): "");
std::string company(get_company_name? read_company(): "");
Report report = get_company_name? Report(name, company): Report();
All of these approaches assume that the Report class is actually copyable.
I don't know if I understood your question correctly but can't you just declare report before the if/else block and then initialize inside it?
Report header;
if (...) {
header = Report();
else
header = Report(name,company);
Or in a shorter way:
Report header; // calls default constructor
if (shouldInitializeWithParams) {
header = Report(name,company);
}
Of course this requires you to have the empty constructor defined.
We don't know whether class Report is copy-able, so better to use pointers.
Report * header;
if (...) {
header = new Report();
else
header = new Report(name,company);
// after all don't forget
delete header;
and of course you should use header pointer like that
header->print_formatted();
The simplest thing that comes to mind is performing a little refactoring on the code flow. Create a function that processes the input and returns the constructed object:
Report loadReport() {
if (user_input()) {
// read input
return Report(name,company);
} else {
return Report();
}
}
Then call the function from main. The small change in the design is the introduction of a function whose single responsibility is creating a Report from user input, which actually makes sense as a function.
You can use an rvalue reference to bind in place to either constructed object.
struct Foo
{
Foo(int bar): bar(bar) {}
int bar
};
Foo&& f = condition ? Foo(4) : Foo(5);
f.bar = 1000;
I'm not sure if I understood your question properly. Apologies if you read the answer and realise that that's the case.
But nevertheless, I think the main strategy would be to make use of constructor overloading. ie, you define constructors for both: the case when no parameters are passed and the case when parameters are passed.
The former(what you refer to as default constructor) will initialise the company and report names to default values. The latter will assign the parameters received, to the comapany and report names.
As for the use of pointers: you can avoid it by 'declaring' a lot of objects of type 'Report'(class). For eg, you can create an array of header(objects).
And then you can 'define' it as and when the user responds.
But by using pointers, you're doing everything in runtime(dynamic assignment) whereas when using arrays(or declaring many objects): the amount is fixed. This can be inefficient.
As of C++17, you can now use std::optional for this task - it avoids dynamic memory allocation, it avoids two-phase construction of the object, and it doesn't require the type to be movable or copyable. It allows you to delay the construction of the object while keeping it on the stack and also still being exception-safe. If you construct it in every branch you can safely use it afterward with no performance penalty. It will also work as a class member allowing you to avoid the problem with the class constructor initializer for it, unlike the rvalue reference solution. Demo: https://gcc.godbolt.org/z/vbe5eh
#include <optional>
struct UseCtorA final {};
struct UseCtorB final {};
struct Report final
{
Report() = delete;
Report(Report const &) = delete;
Report(Report &&) = delete;
Report &operator=(Report const &) = delete;
Report &operator=(Report &&) = delete;
Report(UseCtorA, char c) : v{1} { if(c == 't'){ throw 3; } }
Report(UseCtorB) : v{2} {}
constexpr auto getValue() const noexcept { return v; }
private:
int v;
};
int main(int nargs, char const *const *args)
{
std::optional<Report> report;
if(nargs > 2)
{
report.emplace(UseCtorA{}, args[1][0]);
}
else
{
report.emplace(UseCtorB{});
}
return report->getValue();
}
If you are stuck in an older compiler that only supports C++11, you can make your own really dumb version of std::optional for this express purpose by using a union and placement new:
struct Empty final {};
template<typename T>
struct Optional
{
Optional() noexcept : unused{} {}
~Optional() noexcept(noexcept(v.~T()))
{
if(constructed_successfully)
{
v.~T();
}
}
template<typename... Args>
auto emplace(Args &&... args) -> T &
{
if(constructed_successfully)
{
v.~T();
constructed_successfully = false;
}
T &r = *new (&v) T(std::forward<Args>(args)...);
constructed_successfully = true;
return r;
}
auto operator->() noexcept -> T *
{
return &v;
}
private:
union
{
T v;
[[no_unique_address]] Empty unused;
};
bool constructed_successfully = false;
};
The generated assembly is identical to with std::optional: https://gcc.godbolt.org/z/vzGz9E
Though, I would recommend using an existing library to supplement your lack of access to std::optional instead of rolling your own like I have done above - my version doesn't work for copying or moving.