2
template<typename Container, typename Ret, typename ...Args>
    struct BindImpl {
        template<Ret (Container::*MemberFunc)(Args...)>
        class Callable {
        public:
            inline constexpr Callable (Container *container) :
                m_container(container)
            {}

            inline Ret operator() (Args ...args) const
            {
                return (m_container->*MemberFunc)(std::forward<Args>(args)...);
            }

            inline Function<Ret(Args...)> toFunction() const
            {
                return Function<Ret(Args...)>(*this);
            }

        private:
            Container *m_container;
        };
    };
    template<typename Container, typename Ret, typename ...Args>
    BindImpl<Container, Ret, Args...> DeduceImpl (Ret (Container::*)(Args...));

This code is called like this:

(typename decltype(::AIpStack::BindPrivate::DeduceImpl(&EthIpIface::driverSendIp4Packet)) ::template Callable<&EthIpIface::driverSendIp4Packet>((this)).toFunction())

I'm trying to understand what this code does. It apprently is a way to bind function pointers (like &EthIpIface::driverSendIp4Packet) to something.

The line above is from this macro, which fills this struct member, if anyone is intersted. You may wanna have a loot at Function.

The first part that I don't understand is

template<Ret (Container::*MemberFunc)(Args...)>

For me a template must be followed by typename. Also, what follows typename, is the thing to be substituted for. I don't see how this template makes Callable templated. I don't know where something goes to in Callable<something>.

Also, what is DeduceImpl? Looks like a function declaration but without a definition.

Also, what Container::*MemberFunc means?

Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • Put up a criteria: What would it take for me to accept an answer to my question. – Ted Lyngmo Dec 30 '19 at 04:05
  • `Ret (Container::*MemberFunc)(Args...)` is a pointer to a member function, named `MemberFunc`, to a member of `Container`, which returns type `Ret` and takes arguments of the types in the parameter pack `Args`. Templates can have non-type arguments too, and for this one it wants you to pass the member of `Container` it's going to bind – parktomatomi Dec 30 '19 at 04:08
  • [Won't compile](https://gcc.godbolt.org/z/GtywZp) please share a [mcve] – Aykhan Hagverdili Dec 30 '19 at 04:43
  • Does this answer your question? [Pointer to class data member "::\*"](https://stackoverflow.com/questions/670734/pointer-to-class-data-member) – Davis Herring Dec 30 '19 at 15:21

1 Answers1

4

Firstly, templates can also take in non-type parameters as well as with typename and class. In this case:

template<Ret (Container::*MemberFunc)(Args...)>

This is a template taking a function pointer as a parameter, where Ret is the return type, Container::*MemberFunc is the pointer to a specific member function in Container with Args... referencing variadic arguments. This gives the pointer the identifier MemberFunc. I have a feeling the asterisk following the scope resolution operator confused you, as usually you would receive a compiler error if you used these two together in any other situation but in this specific case these two are considered one token ::* representing this kind of template parameter instead of the two :: and *.


For this line:

BindImpl<Container, Ret, Args...> DeduceImpl (Ret (Container::*)(Args...));

It is a function declaration. This is a function named DeduceImpl that will return a BindImpl struct that takes a function pointer as an argument. I'm inferring that this function is the interface by which you bind the function pointer, hence the (probably) shortened names "Deduce Implementation" and "Bind Implementation" From what I've read, this function is only used for decltype, so there's no actual definition for this function.


For how this template is actually being utilized in this line (reformatted for easier reading):

typename decltype(::AIpStack::BindPrivate::DeduceImpl(&EthIpIface::driverSendIp4Packet))
::
template Callable<&EthIpIface::driverSendIp4Packet>(this).toFunction()

This is a template disambiguator created just so the compiler knows that the actual template is being utilized instead of a less-than comparison operator.

You wouldn't write all of this just to use the template. This line was probably written because it's one of the few ways the template is instantiated in the project.


In summary:

  • template<Ret (Container::*MemberFunc)(Args...)> is a template that takes a function pointer referred to as MemberFunc as a parameter.
  • DeduceImpl returns a BindImpl struct by taking in the function pointer you want to bind.
NaShBe
  • 306
  • 2
  • 8
  • but why `DeduceImpl` has no definition? – Guerlando OCs Dec 30 '19 at 15:22
  • Problem is, DeduceImpl appear nowhere in the project, only there – Guerlando OCs Dec 30 '19 at 19:00
  • Also, what is `((this))`? You wrote with one parenthesis but it's actually double. Does that make a difference? – Guerlando OCs Dec 30 '19 at 20:40
  • If you follow, this value of this is deduces as `Container container` in `Function`, however the `Container container` is never used because the macro actually calls `toFunction`. So why binding `this`? – Guerlando OCs Dec 30 '19 at 20:41
  • This project only (mostly) has header files. It's aimed to be portable, so implementation files are platform-specific and so are not added to the project. `*this` is used to specify that we are running 'Callable' through `operator ()`, which is when the `Container container`, `m_container`, is used. The double parentheses, AFAIK, are no difference from singular parentheses. – NaShBe Dec 30 '19 at 21:31
  • That's strange, the project even contains an example folder https://github.com/ambrop72/aipstack/tree/master/examples, I don't see a reason why it shouldn't be ready for usage. However, my vscode searcher didn't find any DeduceImpl anywhere except as a declaration. The fact that this declaration is on a /misc folder even suggests that it's just an utility and that we shouldn't implement anything by ourselves. – Guerlando OCs Dec 30 '19 at 21:43
  • The example folders are not really part of the library, but a compilable example to demonstrate. It wouldn't make sense to require someone to implement example code. As for the location of the file, I am not really familiar enough with the project to answer that. The lack of any implementation files implies a platform-specific implementation is in order. – NaShBe Dec 30 '19 at 21:57
  • 1
    Hi, I talked with the developer, he said that "DeduceImpl is only declared, never defined, since that function is never actually called, it is just used within decltype to deduce the types involved in a pointer to member function.". So it explains why there's no definition and no need for it. – Guerlando OCs Dec 31 '19 at 14:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/205173/discussion-between-nashbe-and-guerlando-ocs). – NaShBe Jan 01 '20 at 00:27
  • Hi, author of this code here. This answer is mostly correct except there is no explicit instantiation. The bind expression, up to the end of `Callable<...>`, refers to a Callable template instantiated with specific template parameters (and is therefore a class type). It is simple template instantiation, not explicit instantiation. Then `(this)` invokes a constructor of this class, and `.toFunction()` calls a member function on the constructed `Callable` object. – Ambroz Bizjak Jan 20 '20 at 19:20
  • 1
    I guess it may mislead one to think it's an explicit instantiation due to `::template Callable`, but here template is just a disambiguator, see https://en.cppreference.com/w/cpp/language/dependent_name, search for "template disambiguator". – Ambroz Bizjak Jan 20 '20 at 20:53
  • @AmbrozBizjak thanks for pointing this out, I'll modify my answer accordingly ASAP. – NaShBe Jan 20 '20 at 22:08