Calling overloaded constructor from constructor initialisation list - c++

In the code below, my intent is to call one of two overloaded constructors for the kap (class opacity) based on what arguments are passed to the object of class material:
class opacity{
private:
int mode;
double kap_const;
double kappa_array[10][10];
public:
opacity(double constkap); // picking the constructor sets the mode
opacity(char* Datafile);
double value(double T, double P); // will return a constant or interpolate
};
opacity::opacity(double constkap):mode(1){
kap_const = constkap;
}
opacity::opacity(char* Datafile):mode(2){
// read file into kappa_array...
}
class Matter {
public:
Matter(int i, double k, char* filename); // many more values are actually passed
opacity kap;
int x; // dummy thing
// more variables, call some functions
};
Matter::Matter(int i, double k, char * filename)
:x(k>0? this->kap(x): this->kap(filename) ) {
// ... rest of initialisation
}
This is however not working:
test.cpp: In constructor 'Matter::Matter(int, double, char*)':
test.cpp:32:21: error: no match for call to '(opacity) (void*&)'
test.cpp:32:42: error: no match for call to '(opacity) (char*&)'
test.cpp:32:44: error: no matching function for call to 'opacity::opacity()'
test.cpp:32:44: note: candidates are:
test.cpp:20:1: note: opacity::opacity(char*)
test.cpp:20:1: note: candidate expects 1 argument, 0 provided
test.cpp:16:1: note: opacity::opacity(double)
test.cpp:16:1: note: candidate expects 1 argument, 0 provided
test.cpp:4:7: note: opacity::opacity(const opacity&)
test.cpp:4:7: note: candidate expects 1 argument, 0 provided
The first thing I had tried,
Matter::Matter(int i, double k, char * filename)
:kap(k>0? k: filename) { // use k<0 as a flag to read from filename
// ... rest of initialisation
}
also failed, because "the result of a ternary operator always has to be the same type" for compile-time reasons, as pointed out in a similar question (although they were not explained there, it seems).
Now, the inelegant solution would be to also overload the Matter constructor based on the arguments that the kap constructor should receive, but this is (1) very inelegant, especially since the Matter constructor takes many variables and performs many actions (so a lot of code would be duplicated just to vary the kap part of the constructor initialisation list), and (2) this can get out of hand if there is another class used with Matter that also has different constructors: for M classes with N c'tors, one ends up with N^ M combinations...
Would someone have a suggestion or a work-around? Thanks in advance!

If opacity has a copy constructor, you could accomplish this in the initialization list, avoiding a default constructor, but at the cost of a copy:
Matter::Matter(int i, double k, char * filename)
:kap( ( 0 < k ) ? opacity(k) : opacity( filename ) ) { ... }

You will have to live with adding a default constructor to opacity (which perhaps sets mode to 0 to indicate an invalid mode) and assign to kap in the constructor body.
Matter::Matter(int i, double k, char * filename) {
if(k > 0)
kap = opacity(k);
else
kap = opacity(filename);
}
The parameter k is a runtime value. It is not possible to make types and overloading result depend on runtime values.

To obviate copy overhead, and assuming you have a C++0x compiler, you could give opacity a move constructor and have a static function provide an instance of opacity based on your logic and initialize your kap member with the returned temporary opacity.
You'd probably want to make kappa_array some pointer like auto_ptr<double>. Though if this data is used in a tight-loop, the savings from moveability may be dubious compared to the cost of locality and dereferencing the pointer.
opacity& get_opacity(double k, char * filename) {
if(k > 0)
return opacity(k);
else
return opacity(filename);
}
Matter::Mater(int i, double k, char * filename)
: kap(get_opacity(k, filename) {
//...
}
opacity::opacity(opacity&& other)
: mode(other.mode),
kap_const(other.kap_const),
kappa_array(std::move(kappa_array)) { }
Please don't test me on this, I'm pretty new with move semantics and rvalue references myself...

You can't use a ternary operator to select function overrides because the result of the operator only has a single type. In the case where the different branches have different types, they will be coerced to the result type or there will be a compile time error. See http://en.wikipedia.org/wiki/%3F:#Result_type
It couldn't really be any other way. Types need to be known by the compiler at compile time, but the result of the operation isn't known until run time.

Related

Write a function that only accepts literal `0` or literal `1` as argument

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.

Returning a value from a map matching the type of the return value

I received the following error
In file included from /Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:2:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:439:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:628:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1673:31: error: no matching constructor for initialization of 'Vertex'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
And here is an abridged version of the relevant portion of my code:
class Vertex {
public:
int label;
vector<Vertex> adjacent_vertices;
Vertex(const int l) : label(l) { }
Vertex(const int l, vector<Vertex> adjacents) : label(l), adjacent_vertices(adjacents) { }
Vertex(const Vertex& other_vertex) : label(other_vertex.label), adjacent_vertices(other_vertex.adjacent_vertices){ }
};
class Graph {
public:
unordered_map<int, Vertex> vertices;
protected:
Vertex getmake_vertex(const int v) {
if (vertices.find(v) == vertices.end() ) {
// not found, make new vertex
vertices[v] = Vertex(v);
}
return vertices[v];
};
};
I have confirmed that running this with everything else commented out produces a compiler error. Can someone explain to my why this occurs and how I can fix it? Here is a gist with the full compiler output.
When you say vertices[v] = Vertex(v); it has to create a Vertex for the key v (before the assignment), but Vertex has no default constructor.
What you should use is vertices.insert(make_pair(v, Vertex(v))) or even vertices.emplace(v, Vertex(v))
This also applies to return vertices[v];. Even though you and I know that there is always a value for v already by the time this return statement is hit, the compiler doesn't and still has to generate the code to potentially make one, and that is causing an error.
Setting it to return vertices.find(v)->second; will fix that part. No need to check and make sure the find value isn't end since we just put it in if it wasn't there.
Using operator[] requires the mapped_type (Vertex) in your case to be default constructible1, because it inserts a default-constructed1 mapped_type if key doesn't exist in the map. This is a run-time decision, so even if the key actually exists you still need the default constructor at compile-time.
In C++17, use try_emplace:
Vertex getmake_vertex(const int v) {
return vertices.try_emplace(v, v).first->second;
}
Otherwise, use insert or emplace.
Vertex getmake_vertex(const int v) {
return vertices.insert({v, v}).first->second;
}
(You may need to use Vertex(v) if you make the Vertex(int) constructor explicit, which you probably should.)
None of those actually inserts if the key is already in the map. All three
returns a pair<iterator, bool> with the iterator pointing to the element with the specified key.
1 Not quite true, but true enough for our purposes.
If I read this part of the error message(s) correct, it requires a default constructor for Vertex; especially this:
requires 2 arguments, but 0 were provided
/Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:14:5: note: candidate constructor not viable: requires single argument 'l', but no arguments were provided
Vertex(const int l) : label(l) { }
^
/Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:16:5: note: candidate constructor not viable: requires single argument 'other_vertex', but no arguments were provided
Vertex(const Vertex& other_vertex) : label(other_vertex.label), adjacent_vertices(other_vertex.adjacent_vertices){ }
^
/Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:15:5: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
Vertex(const int l, vector<Vertex> adjacents) : label(l), adjacent_vertices(adjacents) { }

do_decimal_point and do_thousands_sep Not Working

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.

optimize output value using a class and public member

Suppose you have a function, and you call it a lot of times, every time the function return a big object. I've optimized the problem using a functor that return void, and store the returning value in a public member:
#include <vector>
const int N = 100;
std::vector<double> fun(const std::vector<double> & v, const int n)
{
std::vector<double> output = v;
output[n] *= output[n];
return output;
}
class F
{
public:
F() : output(N) {};
std::vector<double> output;
void operator()(const std::vector<double> & v, const int n)
{
output = v;
output[n] *= n;
}
};
int main()
{
std::vector<double> start(N,10.);
std::vector<double> end(N);
double a;
// first solution
for (unsigned long int i = 0; i != 10000000; ++i)
a = fun(start, 2)[3];
// second solution
F f;
for (unsigned long int i = 0; i != 10000000; ++i)
{
f(start, 2);
a = f.output[3];
}
}
Yes, I can use inline or optimize in an other way this problem, but here I want to stress on this problem: with the functor I declare and construct the output variable output only one time, using the function I do that every time it is called. The second solution is two time faster than the first with g++ -O1 or g++ -O2. What do you think about it, is it an ugly optimization?
Edit:
to clarify my aim. I have to evaluate the function >10M times, but I need the output only few random times. It's important that the input is not changed, in fact I declared it as a const reference. In this example the input is always the same, but in real world the input change and it is function of the previous output of the function.
More common scenario is to create object with reserved large enough size outside the function and pass large object to the function by pointer or by reference. You could reuse this object on several calls to your function. Thus you could reduce continual memory allocation.
In both cases you are allocating new vector many many times.
What you should do is to pass both input and output objects to your class/function:
void fun(const std::vector<double> & in, const int n, std::vector<double> & out)
{
out[n] *= in[n];
}
this way you separate your logic from the algorithm. You'll have to create a new std::vector once and pass it to the function as many time as you want. Notice that there's unnecessary no copy/allocation made.
p.s. it's been awhile since I did c++. It may not compile right away.
It's not an ugly optimization. It's actually a fairly decent one.
I would, however, hide output and make an operator[] member to access its members. Why? Because you just might be able to perform a lazy evaluation optimization by moving all the math to that function, thus only doing that math when the client requests that value. Until the user asks for it, why do it if you don't need to?
Edit:
Just checked the standard. Behavior of the assignment operator is based on insert(). Notes for that function state that an allocation occurs if new size exceeds current capacity. Of course this does not seem to explicitly disallow an implementation from reallocating even if otherwise...I'm pretty sure you'll find none that do and I'm sure the standard says something about it somewhere else. Thus you've improved speed by removing allocation calls.
You should still hide the internal vector. You'll have more chance to change implementation if you use encapsulation. You could also return a reference (maybe const) to the vector from the function and retain the original syntax.
I played with this a bit, and came up with the code below. I keep thinking there's a better way to do this, but it's escaping me for now.
The key differences:
I'm allergic to public member variables, so I made output private, and put getters around it.
Having the operator return void isn't necessary for the optimization, so I have it return the value as a const reference so we can preserve return value semantics.
I took a stab at generalizing the approach into a templated base class, so you can then define derived classes for a particular return type, and not re-define the plumbing. This assumes the object you want to create takes a one-arg constructor, and the function you want to call takes in one additional argument. I think you'd have to define other templates if this varies.
Enjoy...
#include <vector>
template<typename T, typename ConstructArg, typename FuncArg>
class ReturnT
{
public:
ReturnT(ConstructArg arg): output(arg){}
virtual ~ReturnT() {}
const T& operator()(const T& in, FuncArg arg)
{
output = in;
this->doOp(arg);
return this->getOutput();
}
const T& getOutput() const {return output;}
protected:
T& getOutput() {return output;}
private:
virtual void doOp(FuncArg arg) = 0;
T output;
};
class F : public ReturnT<std::vector<double>, std::size_t, const int>
{
public:
F(std::size_t size) : ReturnT<std::vector<double>, std::size_t, const int>(size) {}
private:
virtual void doOp(const int n)
{
this->getOutput()[n] *= n;
}
};
int main()
{
const int N = 100;
std::vector<double> start(N,10.);
double a;
// second solution
F f(N);
for (unsigned long int i = 0; i != 10000000; ++i)
{
a = f(start, 2)[3];
}
}
It seems quite strange(I mean the need for optimization at all) - I think that a decent compiler should perform return value optimization in such cases. Maybe all you need is to enable it.

C++ Array initialization

the code below gives compilation error when I try to create test t[2];
because there is no default constructor for this.
But if I create Test t[2] = {test(1,2), test(2,3)}; Then it works fine.
1)But think of a situation, if we want to create more then 100 array element. We need to create 100 element in the curly braces like..
Test t[100] = {test(1,2), test(1,2)……/100 times/};
The above code is difficult to maintain.
One more solution is to create public member function which takes 2 integers and run in a loop. This solves the problem but i want to know any other good method.
2) If I create it using new
Test *t = new test[10];
I get compilation error(No default constructor). How to solve this.
class test
{
int _a;int _b;
public:
test(int a, int b);
void display();
};
int _tmain(int argc, _TCHAR* argv[])
{
test t[10];
for (int i = 0 ; i< 10; i++)
t[i].display();
}
In order to construct your 10 elements in the array the compiler somehow has to instaciate them through a constructor. For arrays only a default constructor (taking no arguments) can bes used, as you can not pass any arguments to the elements in the array. Therfor you have to proved a constructor
test::test()
taking no arguments.
In your example what do you expect to be displayed?
If you know that, you can write a Default CTor (one that has no parameters) and set your values to the defaults.
An example of the Default CTor:
// Variant 1: Use the initialization list
test()
: a(-1)
, b(-1)
{
}
// OR
// Variant 2: Do it in the CTor's body
test()
{
a = -1;
b = -1;
}
Note: You can write several CTors (it's called "overloading"). One that takes no parameters and sets default values and others that take parameters and set those values.
You can also define a constructor with default values for all parameters which will be used as the default constructor.
test(int a = 0, int b = 0) :_a(a), _b(b) {}
Since all parameters have default values, this constructor will be used as the default. Leaving out the initialization list or not initializing the member variables in the body of the constructor may give you random data values. Some systems may zero all memory allocations, but some do not.