Defaulting multiple arguments - c++

I have a class that looks like the following:
class Example {
Foo1 f1;
Foo2 f2;
Foo3 f3;
size_t hash;
};
Please note that FooX will be always different classes. I want to add a constructor which assigns the value to each fX element and computes the hash (for cacheing its value).
However I want to be able to omit any number of arguments and assign a default value to the corresponding member of the class. Obviously I could use the defaulting feature of C++:
Example(Foo1 f1 = DEFAULT4F1, Foo2 f2 = DEFAULT4F2, Foo3 f3 = DEFAULT4F3);
However for being able to omit f2, I need to omit f3, which I might want to specify. Then I could write a constructor for each possible order, but the amount of constructors grows with the factorial of elements, so for this case:
Example(Foo1 f1 = DEFAULT4F1, Foo2 f2 = DEFAULT4F2, Foo3 f3 = DEFAULT4F3);
Example(Foo1 f1 = DEFAULT4F1, Foo3 f3 = DEFAULT4F3, Foo2 f2 = DEFAULT4F2);
Example(Foo2 f2 = DEFAULT4F2, Foo1 f1 = DEFAULT4F1, Foo3 f3 = DEFAULT4F3);
Example(Foo2 f2 = DEFAULT4F2, Foo3 f3 = DEFAULT4F3, Foo1 f1 = DEFAULT4F1);
Example(Foo3 f3 = DEFAULT4F3, Foo1 f1 = DEFAULT4F1, Foo2 f2 = DEFAULT4F2);
Example(Foo3 f3 = DEFAULT4F3, Foo2 f2 = DEFAULT4F2, Foo1 f1 = DEFAULT4F1);
I don't want to specify the same constructor that many cases, because in my real case there are more than 3 parameters. I also want to consider forwarding their values (Foo&& arg and std::forward(arg))
Edit:
To sum up: desired constructor would act like this, but being able to omit any of the parameters, and use a default value for them
Example(Foo1&& f1, Foo2&& f2, Foo3&& f3) :
f1(std::forward(f1)),
f2(std::forward(f2)),
f3(std::forward(f3)),
hash(doSomethingForIt())
{
}

This is a workaround, not an initialization in C++ sense.
Because you need in advance all members of your class, you already know them:
class Example {
Foo1 f1;
Foo2 f2;
Foo3 f3;
size_t hash;
//default ctor, initializes all members with defaults defined somewhere
Example() : f1(defaultF1), f2(defaultF2), f3(defaultF3) {}
....
Now we add setters:
Example& setFoo1(Foo1 fo1 = defaultF1)
{
f1 = fo1;
return *this;
}
Example& setFoo2(Foo2 fo2 = defaultF2)
{
f2 = fo2;
return *this;
}
....
}; //class Example
And then the usage:
Example exple;
exple.setFoo2(someF2value).setFoo1(someF1value); //not all setFooX are used
Notice that we can call setFooX() in any order.

Adding to Ripi2 solution I would also add a method which computes the hash and returns an r-value.
class Example
{
Foo1 f1 = DEFAULT4F1;
Foo2 f2 = DEFAULT4F2;
Foo3 f3 = DEFAULT4F3;
size_t hash;
auto doSomethingForIt();
public:
Example() = default;
auto& initFoo1(Foo1&& f) { f1 = std::move(f); return *this; }
auto& initFoo2(Foo2&& f) { f2 = std::move(f); return *this; }
auto& initFoo3(Foo3&& f) { f3 = std::move(f); return *this; }
auto&& finalize()
{
hash = doSomethingForIt();
return std::move(*this);
}
};
This allows for stuff like this to work.
void foo(Example&& e);
foo(Example().initFoo1(f1).initFoo3(f3).initFoo2(f2).finalize());

I propose a solution where the constructor takes a parameter pack of arguments, forms a tuple with it and tries to reorder the tuple to the desired configuration.
#include <tuple>
namespace details {
// General case
// In : the type of input tuple with the out-of-order elements
// Out : a tuple with the desired element order
template<class In, class Out>
struct sort_tuple_impl;
// Implementation with specialization
template<class In, class ... T>
struct sort_tuple_impl<In, std::tuple<T...>>
{
static auto sort(In && params)
{
// Construct another tuple using the output type's elements
// to determine the order of the elements
return std::make_tuple(std::move(std::get<T>(params))...);
}
};
}
// Reorders a tuple
template<class Out, class In>
Out sort_tuple(In && params) {
return details::sort_tuple_impl<In, Out>::sort(std::move(params));
}
// Example types
struct Foo1 {};
struct Foo2 {};
struct Foo3 {};
class Example
{
public:
// A constructor that takes any kind and number of argument
template<class ... T>
explicit Example(T&& ... params) :
// Make a tuple with the arguments and reorder it according to `decltype(f)`
f{sort_tuple<decltype(f)>(std::make_tuple(std::forward<T>(params)...))}
{ }
private:
// The elements you want to be able to initialize
std::tuple<Foo1, Foo2, Foo3> f;
};
Usage example :
int main()
{
Foo1 f1;
Foo2 f2;
Foo3 f3;
Example e1{ f1, f2, f3 };
Example e2{ f2, f1, f3 };
Example e3{ f3, f2, f1 };
Example e4{ f3, f2 ,f1 };
// These fail to compile
// Example e5{ f1 };
// Example e6{ f1, f1, f2};
// Example e7{ f2, f3, f1, f3 };
}
Note that if the user provides the same Foo more than once or fails to provide one this will produce a compiler error because std::get fails if the requested type is not present exactly once. From std::get :
Extracts the element of the tuple t whose type is T. Fails to compile unless the tuple has exactly one element of that type.
It doesn't produce great error messages, but it prevents mistakes.
Edit : This fails the apparent requirement that some elements can be omitted. But I'll leave it here nonetheless as it may be useful. Perhaps another templated function could be used to add the default values to the missing elements.

I gave a second try to François Andrieux's solution and I achieved my requirements. Here is a working example (C++17) of it:
#include <tuple>
#include <iostream>
//Make a unique class for each foo, to prevent implicit casting
template <typename P>
struct Foo{
constexpr Foo(int x) : x(x) {}
int x;
};
using Foo1=Foo<struct Phatom_1>;
using Foo2=Foo<struct Phatom_2>;
using Foo3=Foo<struct Phatom_3>;
//Example class
class Example {
public:
//Default constructor, assingns default falues to all members
Example() :
f1(DEFAULT_F1),
f2(DEFAULT_F2),
f3(DEFAULT_F3)
{
}
template<typename... Types>
Example(Types&&... t) : Example() { //First of all, calls the default constructor
auto paramTpl = std::make_tuple(std::forward<Types>(t)...); //Creates a tuple with the parameters
assign(f1, paramTpl);
assign(f2, paramTpl);
assign(f3, paramTpl);
}
void show() const{
std::cout << "f1=" << f1.x << ", f2=" << f2.x << ", f3=" << f3.x << std::endl;
}
private:
static constexpr auto DEFAULT_F1 = Foo1(1);
static constexpr auto DEFAULT_F2 = Foo2(32);
static constexpr auto DEFAULT_F3 = Foo3(-1);
template<typename Type, typename... Types>
static void assign(Type& el, std::tuple<Types...> tpl){
struct has_type : std::disjunction<std::is_same<Type, Types>...>{};
if constexpr (has_type::value){
el = std::move(std::get<Type>(tpl));
}
}
Foo1 f1;
Foo2 f2;
Foo3 f3;
};
int main(){
Example ex1;
ex1.show();
Example ex2(Foo1(1), Foo3(1), Foo2(1));
ex2.show();
Example ex3(Foo1(2), Foo3(2));
ex3.show();
return 0;
}
Edit: I have simplified a bit

Related

Can we write a function which returns a function pointer to a function template?

Is it possible to write a function or method which can return a pointer to a template function or template method?
Example:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
// static auto GetPtr() { return X1::Do; } // how to write such a function?
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
//static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic(true, X1::Do, X2::Do);
// should be replaced by:
// auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
If I compile the above out-commented functions, I got from gcc:
main.cpp:1845:39: error: unable to deduce 'auto' from 'X1::Do'
Background: I am currently trying to understand the overload resolution in same cases. In the given case you see that the overload for int is taken because one function pointer only has an int parameter so the second pointer overload can be found.
I was triggered by that question: Ternary operator applied to different lambdas produces inconsistent results
Here in an answer was suggested, that a lambda should be able to provide a conversion operator to a function pointer... and I did not see it :-)
The compiler doesn't "know" in advance all your uses for X1::GetPtr (generally). It seems you are expecting the compiler to 1. recognize it is a template 2. recognize all uses for the function, and see if it can deduce all instantiations needed for the template "for free", so to speak - in your case only the use in magic, but this is not general.
There is no such mechanism in C++ and the compiler must know the type of the function when it parses it, or recognize it as a template (and not guess it).
Simply put, I think you are expecting the compiler to do something too difficult, and it can't. As such, you will have to do the template resolution yourself:
template<typename N>
static auto GetPtr() { return &X1::Do<N>; }
and call it with
magic(true, X1::GetPtr<int>(), X2::GetPtr());
No you cannot return a pointer to a function template, because a function template is not a function. It is a template.
// static auto GetPtr() { return X1::Do; } // how to write such a function?
You need & to get a pointer to a member function, though Do is not a member function it is a member function template. You could return a pointer to X1::Do<int> or to X1::Do<double> but there is no pointer to X1::Do.
You can however return a functor with an overloaded call operator and that operator can be a template:
struct foo {
template <typename T>
void operator()(const T& t) {}
void operator()(int x){}
};
foo magic() { return foo{}; }
int main() {
magic()(3); // calls operator()(int)
magic()("hello world"); // calls operator()<const char[12]>
}
After rereading your question and the Q&A you link, I think you are maybe looking for this:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
static auto GetPtr() { return &X1::Do<int>; }
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
As stated above, you cannot get a member function pointer to X1::Do but you can get a pointer to X1::Do<int>.
And as you are refering to conversion of lambdas to function pointers: Also lambdas with auto argument can only be converted to function pointers after choosing the argument type. Consider the example from cppreference:
void f1(int (*)(int)) {}
void f2(char (*)(int)) {}
void h(int (*)(int)) {} // #1
void h(char (*)(int)) {} // #2
auto glambda = [](auto a) { return a; };
f1(glambda); // OK
f2(glambda); // error: not convertible
h(glambda); // OK: calls #1 since #2 is not convertible
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
It is not possible to get a pointer to function of type auto(auto) (it isn't a type of a function to begin with). In all the calls above, after the conversion there is no auto anymore. Instead the requested type is deduced and a conversion to the respective function pointer is done.

Initialize a lambda function in the body of a class constructor

I can compile the following code without any problem (using gcc 11.1.0):
#include <iostream>
template <typename Func>
class K {
Func f;
public:
K(Func _f): f{_f} {};
void do_thing(int x) {f(x);};
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl;};
K kl{f};
kl.do_thing(5);
return 0;
}
however I would like to perform some check in the constructor of the class K (for instance some std::is_convertible_v inside some bool function), so I tried to modify the code to
#include <iostream>
template <typename Func>
class K {
Func f;
public:
K(Func _f) {
...
f = _f;};
void do_thing(int x) {f(x);};
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl;};
K kl{f};
kl.do_thing(5);
return 0;
}
which however gives me some error message
error: use of deleted function ‘main()::<lambda(int)>::<lambda>()’
and then
note: a lambda closure type has a deleted default constructor
This confuses me a lot since I cannot understand how it is possible that the former piece of code could compile since the lambda function has not default constructor.
Question
How can I set my f inside the body of the constructor? (This is just a MWE and in my case the class is a bit more complex and the checks I mentioned before make sense.)
How can I initialize my f inside the body of the constructor?
You can't. f = _f; inside the constructor body is assignment but not initialization. So f will be default-initialized firstly, then enter the constructor body (to perform assignment).
You might use std::function instead; which could be default-initialized, then you can assign it in constructor body.
BTW: Since C++20 your code will compile fine even it might not work as you expected (depending on the ... part). For lambdas,
If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything).
Is this what you are looking for?
It is the generic solution, not making any assumptions on the signature of Fn
#include <iostream>
#include <utility>
template <typename Fn>
class K
{
public:
explicit K(const Fn& fn) :
m_fn{ fn }
{
};
template<typename... args_t>
auto do_thing(args_t&&... args)
{
return m_fn(std::forward<args_t>(args)...);
}
private:
Fn m_fn;
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl; };
K kl{ f };
kl.do_thing(5);
}

Aggregate initialization pre-C++17

Consider the following class hierarchy, made from aggregates:
struct Foo {
int k;
double d;
};
struct Bar : Foo {
int i;
};
Now, let's say I would like to initialize an object of type Bar from an object of type Foo, giving extra argument for i. (For reason to dull to discuss here, adding a constructor to Bar which accept Foo and int, or modifying definition of Bar or Foo in any other way is out of question). In C++17 I would use aggregate initialization:
auto make(const Foo& f) {
return Bar{f, 42};
}
This is not available in C++14. Is there anything else I can do mimic desired behavior in C++14? I am trying to avoid something like
auto make(const Foo& f) {
Bar b;
b.k = f.k;
b.d = f.d;
b.i = 42;
return b; // or return Bar{f.k, f.d, 42};
}
Where the thing I am trying to avoid is making make aware of internals of Foo - i.e. make is fine to know how to initialize extra members of Bar, but would prefer not to initialize members of Bar which are common with Foo.
auto make(const Foo& f) {
Bar b;
static_cast<Foo&>(b) = f;
b.i = 42;
return b;
}

Need to invoke non-static method without object

Consider the following piece of C++ code:
class Foo {
public:
int a;
};
class Bar {
public:
int w = 1;
bool are_foos_equal(Foo* f1, Foo* f2) { return f1->a * w == f2->a * w; }
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
Now, this doesn't compile because in the operator () of FooEqual I cannot invoke non-static are_foos_equal.
My question is: is it possible for fooset to use are_foos_equal somehow? I know that I could just make are_foos_equal static but the example code I gave is just so that I could state my problem which, unfortunately, occured in a much bigger project, and even if that means that the design is somewhat wrong, I'd like to rescue it by some hacks, if possible.
EDIT
I added a non-static member variable w to Bar to emphasize "non-staticness" of are_foos_equal.
Move are_foos_equal() outside of the class and make it a free function. It doesn't make sense that it should be a member of Bar. Example:
class Foo {
public:
int a;
};
bool are_foos_equal(Foo* f1, Foo* f2)
{return f1->a == f2->a;}
class Bar {
public:
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
You could maintain a reference to the parent Bar object in FooEqual:
Bar() : fooset{10, FooHash{}, FooEqual{*this}}
{}
struct FooEqual {
Bar& parent;
bool operator () (Foo* f1, Foo* f2) const {
return parent.are_foos_equal(f1, f2);
}
};
Because of how the constructors are declared in std::unordered_set you need to provide a bucket count, which is a bit unfortunate. You could get the default from a default-constructed std::unordered_set if you felt like it.
The correct option would definitely be to make are_foos_equal static. I would strongly suggest doing this instead of a hack. The larger the project, the cleaner it needs to be so that it doesn't devolve into an unmaintainable mess.
But if that is seriously not an option, I see a few other possibilities:
Create a Bar object on the fly inside FooEqual:
return Bar().are_foos_equal(f1, f2);
Have FooEqual store a static Bar object for this purpose:
bool operator() (Foo* f1, Foo* f2) const {
static Bar bar;
return bar.are_foos_equal(f1, f2);
}
Invoke Undefined Behaviour, invoke are_foos_equal on a null pointer and hope that it doesn't do anything bad. I strongly discourage this:
return static_cast<Bar*>(nullptr)->are_foos_equal(f1, f2);
Here it could be trivial, because are_foos_equal could be static, as it neither use not change anything in this
=> first way just declare are_foos_equal static.
Alternatively, if the called function cannot be static because it uses or changes it object, you will have to change FooEqual to contain a Bar object (or a pointer or reference to it) . Because C++ is not java: inner classes have no hidden pointer to an object of enclosing class.
=> second way add a reference to a Bar in FooEqual and set it at construction time:
struct FooEqual {
const Bar &bar;
FooEqual(const Bar& bar): bar(bar) {};
bool operator () (Foo* f1, Foo* f2) const {
return bar.are_foos_equal(f1, f2);
}

'auto' and explicit variable declaration behaving differently

I have something like this:
class Bar;
class Foo()
{
public:
Foo() : bar(new Bar());
Bar& GetBar() { return *bar.get(); }
private:
std::unique_ptr<Bar> bar;
};
void main()
{
Foo foo;
auto bar1 = foo.GetBar();
auto bar2 = foo.GetBar(); //address of bar2 != address of bar1. why?
Bar& bar3 = foo.GetBar();
Bar& bar4 = foo.GetBar(); //address of bar3 == address of bar4.
}
It seems the 'auto' variables are copies as I don't get Bars back with the same memory address.
If I explicitly define the variables as Bar references (Bar&) then everything works as I would expect.
I should mention I'm compiling in vs2012. What's going on here?
Thanks.
auto bar1 = … always declares a copy. auto &&bar1 selects the closest possible reference type, which is what you want.
auto && is the perfect forwarding idiom.
You can also use other compound types with auto, such as auto const & or auto * if you want to be specific.
auto works like template argument deduction. bar1 and bar2 have types Bar, so they are independent copies; bar3 and bar4 have type Bar & and are references to the same *foo.bar.
Code:
X& getter() {
static X value;
return value;
}
print("X:");
X x0 = getter();
auto x0a = getter();
x0.printAddress();
x0a.printAddress();
print("X&:");
X& x1 = getter();
auto& x1a = getter();
x1.printAddress();
x1a.printAddress();
print("const X&:");
const X& x2 = getter();
const auto& x2a = getter();
x2.printAddress();
x2a.printAddress();
print("X&&:");
print("Rvalue can't be bound to lvalue");
X&& x3 = getter();
auto&& x3a = getter();
x3.printAddress();
x3a.printAddress();
Result:
X:
0037F807
0037F7FB
X&:
00D595BA
00D595BA
const X&:
00D595BA
00D595BA
X&&:
Rvalue can't be bound to lvalue
00D595BA
Conclusion:
auto means: "replace me with type, unless I am auto&& then find the most suitable form".