Here is my code:
struct S
{
int f() { return 1; }
int g(int arg = f()) { return arg; }
};
int main()
{
S s;
return s.g();
}
This fails to compile with the error:
error: cannot call member function 'int S::f()' without object
Trying this->f() doesn't work either, as this may not be used in that context.
Is there a way to make this work, still using the default argument?
Of course it can be worked around by not using default arguments at all:
int g(int arg) { return arg; }
int g() { return g(f()); }
however that gets verbose considering that in the "real code" there are more parameters before arg, and several functions following this pattern. (And even more ugly if there were multiple default arguments in the one function).
NB. This question looks similar at first, but in fact he is asking how to form a closure, which is a different problem (and the linked solution doesn't apply to my situation).
You can only use members there if they are static. From a C++11 draft standard (n3299), §8.3.6/9:
Similarly, a non-static member shall not be used in a default argument, even if it is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is
used to form a pointer to member (5.3.1).
E.g., this works:
struct S {
static int f() { return 1; }
int g(int arg = f()) { return arg; }
};
int main()
{
S s;
return s.g();
}
This also works (I think that's what the first expression means):
struct S {
int f() { return 42; }
int g(int arg);
};
static S global;
int S::g(int arg = global.f()) { return arg; }
int main()
{
S s;
return s.g();
}
As for this, it is indeed not allowed (§8.3.6/8):
The keyword this shall not be used in a default argument of a member function.
The default arguments page on cppreference.com has a lot of details regarding the subject—it can get quite complex.
If you are allowed to use experimental features from C++17, you can use std::optional from the STL (see here for further details).
In other terms something like:
int g(std::optional<int> oarg = std::optional<int>{}) {
int arg = oarg ? *oarg : f();
// go further
}
EDIT
As suggested in the comments, the code above should be logically equivalent to the one below:
int g(std::optional<int> oarg = std::optional<int>{}) {
int arg = oarg.value_or(f());
// go further
}
This one is a bit more readable (isn't it?), but please note that it executes f in any case.
If that function is expensive, maybe it doesn't worth it.
I add another answer, that is completely different from the previous one and could solve your issue.
The idea is to use another class and the right mix of explicit and non-explicit constructors.
It follows a minimal, working example:
#include <functional>
#include <iostream>
template<class C, int(C::*M)()>
struct Arg {
std::function<int(C*)> fn;
Arg(int i): fn{[i](C*){ return i; }} { }
explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { }
};
struct S {
int f() { return 1; }
int h() { return 2; }
void g(int arg0,
Arg<S, &S::f> arg1 = Arg<S, &S::f>{},
Arg<S, &S::h> arg2 = Arg<S, &S::h>{})
{
std::cout << "arguments" << std::endl;
std::cout << "arg0: " << arg0 << std::endl;
std::cout << "arg1: " << arg1.fn(this) << std::endl;
std::cout << "arg2: " << arg2.fn(this) << std::endl;
}
};
int main() {
S s{};
s.g(42, 41, 40);
s.g(0);
}
The example shows how you can mix both default parameters and non defaulted ones.
It's quite simple to modify it and let g be a function having an empty argument list, as in the original question.
I'm also quite sure that one can refine the example and end with something better than that, anyway it should be a good point from which to start.
It follows the solution applied to the original example from the question:
#include <functional>
template<class C, int(C::*M)()>
struct Arg {
std::function<int(C*)> fn;
Arg(int i): fn{[i](C*){ return i; }} { }
explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { }
};
struct S {
int f() { return 1; }
int g(Arg<S, &S::f> arg = Arg<S, &S::f>{}) {
return arg.fn(this);
}
};
int main() {
S s{};
return s.g();
}
And that's all, it's possible to do that, even without static methods or global variables.
Of course, we can use our this somehow. It's a matter of bending the language a bit...
Related
All try to do is to make this piece of code
int main() {
if constexpr( ??? ) {
std::cout << "Yes\n";
std::cout << f() << '\n';
std::cout << f(42) << '\n';
}
else {
std::cout << "No\n";
}
return 0;
}
compile if the function f is defined as in any of these examples
// Example 1
int f(int n = 0) { return n; }
// Example 2
int f(int n) { return n; }
int f() { return 0; }
// Example 3
int f(int n) { return n; }
and display Yes for examples 1 and 2, and display No for the example 3.
Is this even possible? I think I've seen someone doing this with SFINAE but I don't remember how exactly it was done and where exactly I saw that. Thank you in advance.
if constexpr can’t protect ill-formed code outside of any template (e.g., in main). The obvious thing to do is to write a template that accepts f itself as a template argument, but to do that you have to reify your overload set. The usual way to do that is as a SFINAE-friendly function object:
template<class F,class=void>
constexpr bool opt=false;
template<class F>
constexpr bool opt<F,decltype(std::declval<F>()(1),void(std::declval<F>()()))> =true;
template<class F> int use(F &&x) {
if constexpr(opt<F>) return x(1)+x();
else return 0;
}
const auto f_=[](auto &&...aa) -> decltype(f(std::forward<decltype(aa)>(aa)...))
{return f(std::forward<decltype(aa)>(aa)...);};
int main() {use(f_);}
In some cases there is also the option of creating a “fake” template that uses calls that are formally dependent but always use the types you want, but that’s impossible for a call f() with no arguments, which is ill-formed (possibly with no diagnostic required) immediately if your f requires an argument since it can’t depend on a template parameter.
I have a C-style function, which stores another function as an argument. I also have an object, which stores a method that must be passed to the aforementioned function. I built an example, to simulate the desired situation:
#include <functional>
#include <iostream>
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
std::function<void(int)> f;
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
TestClass t;
t.f = std::bind(&TestClass::foo, &t, std::placeholders::_1);
foo( t.f.target<void(int)>() );
return 0;
}
What is expected is that it will be shown on screen "2". But I'm having trouble compiling the code, getting the following message on the compiler:
error: const_cast to 'void *(*)(int)', which is not a reference, pointer-to-object, or pointer-to-data-member
return const_cast<_Functor*>(__func);
As I understand the use of "target", it should return a pointer in the format void () (int), related to the desired function through std :: bind. Why didn't the compiler understand it that way, and if it is not possible to use "target" to apply what I want, what would be the alternatives? I don't necessarily need to use std :: function, but I do need the method to be non-static.
This is a dirty little hack but should work
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
static TestClass* global_variable_hack = nullptr;
void hacky_function(int x) {
global_variable_hack->foo(x);
}
int main() {
TestClass t;
global_variable_hack = &t;
foo(hacky_function);
return 0;
}
//can also be done with a lambda without the global stuff
int main() {
static TestClass t;
auto func = [](int x) {
t->foo(x); //does not need to be captured as it is static
};
foo(func); //non-capturing lambas are implicitly convertible to free functions
}
I want to make an array of known size of class functions. To do so, I've tried using typedef, but it hasn't been working out so far.
Also, some functions take no arguments ex. F(), but others do ex. G(int n), and in the typedef, I don't know how to tell it to accept no arguments for some (tried void but it says it is not a type), and to accept arguments for others.
class myClass
{
// An array of void functions
typedef void(myClass::*arrayOfFunctions)();
private:
arrayOfFunctions array[3] = { &myClass::F, &myClass::G, &myClass::H };
void F() { do stuff; }
void G(int n) { do stuff involving n; }
void H() { do stuff; }
};
What I have tried:
I have successfully made an array of void functions in a main with no classes involved which I can call when wanted, so part of the problem seems to be implementing this in a class and using its class functions.
// This works:
typedef void(*arrayOfFunctions)();
void Action1()
{
// stuff 1
}
void Action2()
{
// stuff 2
}
void Action3()
{
//stuff3
}
int main()
{
arrayOfFunctions functionArray[] = { Action1, Action2, Action3 };
// Call Action1
functionArray[0]();
return 0;
)
As was mentioned in comments, it is not possible directly. You cannot store objects of different type in the same array. However, there are ways to achieve what you want. How to get there very much depends on details. Latest when you call the function you need to know how many parameters to pass.
In your example one possibility is to refactor to have only methods with no parameters:
class myClass {
using memFun = void(myClass::*)();
void set_n(int x) { n = x; }
private:
memFun array[3] = { &myClass::F, &myClass::G, &myClass::H };
void F() { do stuff; }
void G() { do stuff involving n; }
void H() { do stuff; }
int n;
};
I changed the name of the alias, because it is just the type of a function pointer not an array. using is easier to read than typedef (it follows the more common x = something style).
When you call the function G the parameter n has to come from somewhere, so instead of passing it directly you can call set_n before iterating the array and call all mehtods without parameter.
It is not clear how you want to use such an array. If you know an element index at compile time, then you could probably use a std::tuple with template argument deduction. For example:
class my_class {
public:
template<std::size_t n, class... Args>
decltype(auto) call_fn(Args&&... args) {
constexpr auto ptrs = get_fn_pointers();
return std::invoke(std::get<n>(ptrs), this, std::forward<Args>(args)...);
}
private:
static constexpr auto get_fn_pointers() {
return std::tuple(&my_class::f, &my_class::g, &my_class::h);
}
void f() {
std::cout << "f()\n";
}
void g(int n) {
std::cout << "g(" << n << ")\n";
}
int h() {
std::cout << "h() => ";
return 9102;
}
};
int main() {
my_class c;
c.call_fn<0>(); // Output: f()
c.call_fn<1>(2019); // Output: g(2019)
std::cout << c.call_fn<2>(); // Output: h() => 9102
}
I want to write a C++ function that adjusts type of second argument based on the first one. so I have something like this:
enum FtnType { FTN_A, FTN_B, FTN_C };
void bar( FtnType foo, const int arg = 0)
{
switch(foo)
{
case 0:
{
void ftnA(arg);
break;
}
case 1:
{
void ftnB();
break;
}
case 2:
{
void ftnC(arg);
break;
}
}
}
Now for case 0 I want arg to be an integer, for case 1 I don't want to use any argument and for case 3 I want arg type to be float. I know I can cast type within the a case but that seems like a bad programming practice. What should be the best approach to solve this problem?
You are trying to mix a fun combination of compile-time and run-time logic. While you might be able to achieve something through the use of templates, by specifying argument one as a compile-time known value, I am not entirely sure it is advisable.
You ask for a best practice, and honestly I feel that a best practice would be to take a step back and rethink your design. Why do you need your function to work so differently based on parameter 1?
If you were to change the value of parameter 2, such as would be the case with variadic arguments used in classic printf like functions, then you would have a source of error that would be difficult to detect at compile time, and even harder to detect run-time.
You might consider a more compile time friendly approach using variadic templates (though I still recommend rethinking your design):
template <typename F, typename... T>
void bar(F func, T... params) {
func(params...);
}
The good thing about this approach, is that accidentally passing the wrong parameter type, or number of parameters, will cause a compile time error. This approach will require you to know the function to execute outside of bar though.
void test1(int a, double b, char c) {
std::cout << "test1(" << a << ", " << b << ", " << c << ")\n";
}
void test2() {
std::cout << "test2()\n";
}
int main() {
bar(test1, 1, 2.1, 'c');
bar(test2);
return 0;
}
This test code can be found running here: http://ideone.com/vU30qn and outputs:
test1(1, 2.1, c)
test2()
It seems to me that depending on the first argument you want to take different type for the second argument. C++ is a strong typed language, which implies that you need to know the value of the first argument at compile time. This brings us in the template territory (me happy). Another issue is that the second argument needs to be passed by reference if you hope to modify it.
enum class FtnType { ftn_a, ftn_b, ftn_c };
template <FtnType type> struct Modify;
template <> struct Modify<FtnType::ftn_a>
{
static auto modify(int& a)
{
ftnA(a);
}
}
template <> struct Modify<FtnType::ftn_b>
{
static auto modify()
{
ftnB();
}
}
template <> struct Modify<FtnType::ftn_c>
{
static auto modify(float& a)
{
ftnC(a);
}
}
and usage:
int main()
{
int a = 24;
float f = 42.f;
Modify<FtnType::ftn_a>::modify(a);
Modify<FtnType::ftn_b>::modify();
Modify<FtnType::ftn_c>::modify(f);
}
This works by having a struct templated by FtnType and each specialization for FtnType has a different signature static modify function.
not sure i'm understanding your problem right, but would an overload like this work?
void bar (int arg)
{
ftnA(arg);
}
void bar (float arg)
{
ftnC(arg);
}
void bar ()
{
ftnB();
}
enum class FtnType {FTN_A, FTN_B, FTN_C};
void bar(FtnType foo, const int arg = 0) {
[&] {
switch(foo) {
case FtnType::FTN_A:
return ftnA(arg);
case FtnType::FTN_B:
return ftnB();
case FtnType::FTN_C:
return ftnC(static_cast<double>(arg));
}
}();
}
Live example
You dont need all these functions and enum. Just use overloaded functions:
void ftn(int arg)
{
std::cout << "I've got an int!" << std::endl;
// Do stuff which is in ftnA
}
void ftn(float arg)
{
std::cout << "I've got an float!" << std::endl;
// Do stuff which is in ftnC
}
void ftn()
{
std::cout << "I've got nothing! :(" << std::endl;
// Do stuff which is in ftnB
}
and simply call
ftn(5); // Will print 'I've got an integer!'
ftn(5.0f); // Will print 'I've got an float!'
ftn(); // Will print 'I've got nothing! :('
What's wrong with the code below? Latest version of g++ and clang both give error. I am sure I am missing something basic here.
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2();
int main()
{
std::cout << f2()::mysize << std::endl;
}
The motivation here is to be able to find out the size of an array using templates using code such as below. I know there are many ways, but just stumbled upon this idea.
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> S<N> f(T (&)[N]);
int main()
{
char buf[10];
std::cout << f(buf)::mysize << std::endl;
}
f2() returns a value, not a type. You'd need to use the . operator on the return value instead of ::
The :: operator requires a type to be named on the lefthand side, while . allows for a value to be named. Your expression f2() does not name a type so it cannot be used in conjunction with ::.
As a side note, with a little more detail in the question we might be able to solve your real problem.
Your program contains two mistakes:
You are using the :: operator to access the member of an object. Use operator . ("dot") instead;
You declare function f2() and invoke it without defining it (this will give you a linker error).
Also, since static member variables are shared among all instances of a class (Z in this case), you do not need an object to access it;
Here is how you could fix your program:
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2() { return Z(); }
int main()
{
// Don't need an object to access a static variable...
std::cout << Z::mysize << std::endl;
// ...but if you really want to, do it this way...
std::cout << f2().mysize << std::endl;
}
Why don't you use this way to find out the size of array by templates:
#include <iostream>
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> int f1(T (&)[N])
{
return N;
}
int main()
{
char buf[10];
std::cout << f1(buf) << std::endl;
}
And this one is closer to your variant:
template<class T, int N> S<N> f(T (&)[N])
{
S<N> foo;
return foo;
}
int main()
{
char buf[10];
std::cout << f(buf).mysize << std::endl;
}
Anyway, you will need to return an object from f and access it's member by ., not by ::.
But it's more probable that second variant will be slower, because first variant is fully compile-time, but in the second variant compiler may miss the optimization and don't optimize out the run-time creation of foo.
I think you need to add const int Z::mysize; after class declaration.