0

I have a class B that takes a template argument such as A. I create a B b and call B::operator()(A a). Regardless of the type of a, b(a) should return a double. I would like to deduce this from outside of B using decltype.

If I had a function B::operator()(), I could do that with

std::declval<B&>()()

This was presented to me in my other question here. (Note, A and B in this question do not match A and B in the previous question.)

If I had a function B::operator()(int i) (no template), I could do that with

std::declval<B>()(int())

although this appears to only work because int is default constructible.

How do I do it when B::operator()() is a template function?

Below is some starting code that compiles on my machine. You shouldn't need to look at it to understand the question.

#include <array>
#include <iostream>
#include <array>

class B {
public:
    B() {};

    template<typename T>
    double operator()(T t) {
        return t();
    }

};

class A {
public:
    A() {};

    double operator()() {
        return 3;
    }
};

int main() {
    A a{};
    B b{};
    std::cout << b(a);

    return 0;
}

Edit:

To clarify, I want to add a line like

using custom_typename = double;

to the above code, except, instead of double, I write something like

using custom_typename = decltype(std::declval<B>()());

modified appropriately to take the return type of B::operator()(T t) instead of B::operator()().

mana
  • 545
  • 4
  • 12
  • If there is a solution that does not use ```std::declval```, that works, and I can edit the question accordingly. – mana Jun 02 '21 at 20:43
  • 4
    If you look back to your last question -- it's `decltype` that determines a type, not `std::declval`. You may not be getting answers because this question presumes that `std::declval` "finds a type". It's not clear to me what you're actually trying to do. – Drew Dormann Jun 02 '21 at 20:56
  • 1
    Why write `b.operator()(a)` and not `b(a)`, which is the point of the existence of the "operator"? – molbdnilo Jun 02 '21 at 22:02
  • @DrewDormann I'm struggling to understand how ```decltype``` and ```declval``` work. I assumed it was clear I would wrap each of my displays in a ```decltype``` afterwards. I was trying to keep notation to a minimum. If you know how to edit the question to make it more clear to people who understand this stuff, please do. – mana Jun 02 '21 at 22:34
  • @molbdnilo that was left-over copy-and-pasted code from when I templated ```operator``` for some reason. Edited. – mana Jun 02 '21 at 22:36

2 Answers2

4

I believe you're looking for

decltype(std::declval<B>()(std::declval<A>())) c = b(a);

Broken down:

         std::declval<B>() //pretend there's a B object
                           std::declval<A>() //pretend there's an A object
         std::declval<B>()(std::declval<A>()) //call b(a) with these 
decltype(std::declval<B>()(std::declval<A>())) //tell me the return type

Or, if you wanted to hide that verbosity:

template<typename T>
using B_return_t = decltype(std::declval<B>()(std::declval<T>()));


B_return_t<A> c = b(a);

http://coliru.stacked-crooked.com/a/4e6e235b47b12cdd

I assume this doesn't count:

auto c = b(a);
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
2

Regardless of the type of a, b(a) should return a double. I would like to deduce this from outside of B using decltype.

You can't generally deduce the first sentence. It is Turing complete to decide the type of an expression in C++; see this question:

C++ templates Turing-complete?

If you want to determine type of b(a) for a specific a, just write: decltype(b(a)); and it shouldn't matter whether class B's operator() is templated or not.

einpoklum
  • 118,144
  • 57
  • 340
  • 684