0

I figured I could initialize a type that takes a callable with std::bind to a member function at top level. However, I seem to make a mistake. I just can't point my fingers where. Compiler errors seem pretty arbitrary...

Demo

#include <functional>
#include <type_traits>
#include <cstdio>

template <typename Callable>
struct timer
{
    template <typename = std::enable_if_t<std::is_invocable_v<Callable>, void>>
    timer(Callable func)
        : func_ {func}
    {
    }

    void invoke() const {
        func_();
    }

    Callable func_;
};

struct some_struct
{
    void do_something() {
        timer_.invoke();
    }

    void request() {
        printf("Hello\n");
    }

    const timer<decltype(std::bind(&some_struct::request, some_struct*))> timer_ { std::bind(&some_struct::request, this) };
};

int main()
{
    some_struct obj;
    obj.do_something();
}

EDIT: Here's the errors (gcc 12.2):

<source>:31:70: error: expected primary-expression before '*' token
   31 |     const timer<decltype(std::bind(&some_struct::request, some_struct*))> timer_ { std::bind(&some_struct::request, this) };
      |                                                                      ^
<source>:31:71: error: expected primary-expression before ')' token
   31 |     const timer<decltype(std::bind(&some_struct::request, some_struct*))> timer_ { std::bind(&some_struct::request, this) };
      |                                                                       ^
<source>:31:73: error: template argument 1 is invalid
   31 |     const timer<decltype(std::bind(&some_struct::request, some_struct*))> timer_ { std::bind(&some_struct::request, this) };
      |                                                                         ^
<source>:31:123: error: cannot convert '<brace-enclosed initializer list>' to 'const int' in initialization
   31 |     const timer<decltype(std::bind(&some_struct::request, some_struct*))> timer_ { std::bind(&some_struct::request, this) };
      |                                                                                                                           ^
<source>: In member function 'void some_struct::do_something()':
<source>:24:16: error: request for member 'invoke' in '((some_struct*)this)->some_struct::timer_', which is of non-class type 'const int'
   24 |         timer_.invoke();
      |         

   ^~~~~~
glades
  • 3,778
  • 1
  • 12
  • 34
  • 1
    You are trying to write a type as as an argument to a function call (`some_struct*`). That doesn't make syntactical sense. Use [`std::invoke_result_t`](https://en.cppreference.com/w/cpp/types/result_of) to determine the type of a call result from types instead of expressions. But what is the purpose of `timer_`? If you want to be able to modify the callable it stores later, `timer` should store a `std::function`, not the callable type itself, which will differ between different callables even with the same signature. – user17732522 Aug 29 '22 at 11:08
  • Also `template , void>>` doesn't work for SFINAE. It will cause a hard compilation error if `Callable` is not invocable. Since you are using C++20, you can simply use a `requires` clause instead of `std::enable_if_t` and since it is constraining `Callable` it should go after `template ` not on the constructor. – user17732522 Aug 29 '22 at 11:12
  • @user17732522 I know but I thought that decltype just needs the types, not actual values. So if I change it to "this" it will issue another error: `error: invalid use of 'this' at top level`. How do I resolve this? Also I don't want to modify the callable after initialization (adapted in example for constness) – glades Aug 29 '22 at 11:33
  • @user17732522 I just recently switched to C++20, I will have a look at concepts now – glades Aug 29 '22 at 11:35
  • @glades to get an expression of a type without having an actual object you can use `std::declval` in an unevaluated operand such as `decltype`: `std::declval()` – user17732522 Aug 29 '22 at 11:41
  • @user17732522 Ahh that's what declval is for! Thank you fixed it on this bases! :) – glades Aug 29 '22 at 18:57

0 Answers0