3

Let's imagine I have some complicated templated function and I want to test that it works as expected. In particular that when invoked with certain arguments that type of function is determined only by first argument. For example:

template<typename T>
bool less(const T& x, const std::type_identity_t<T>& y){
    return x < y;
}

Here I would like to check something (with static_assert or some test framework expect) that only first argument determines the signature of the function, something like:

  std::is_same_v<decltype(less(short{1}, long{2})) , decltype(less(short{1}, double{2}))>;

But obviously this does not work since decltype will give me the result of function invocation, not the type of the function that is instantiated when I give it arguments I gave it.

Is there a way to do this(assume I can not modify the function, e.g. make it a functor with typedefed T or change it any other way)?

I tried searching for this, failed, I guess somebody asked this already but I could not find the question.

note: I know about testing behaviors, not implementation. Example is just tiny example, not something realistic.

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • You can do this from outside C++: https://stackoverflow.com/questions/20092672/how-to-inspect-the-overload-resolution-set-for-a-given-call-site – Etienne Laurin Aug 30 '21 at 01:37
  • 1
    It seems like the only way is to specialize the tester for each testee functions since we can't get the deduced template type https://stackoverflow.com/questions/18369128/how-can-i-see-the-type-deduced-for-a-template-type-parameter – 김선달 Aug 30 '21 at 03:27

2 Answers2

0

This isn't a full answer, but something like this should_convert_to might work to test the less function:

#include <type_traits>

template <typename expected>
struct should_convert_to{
    template <typename actual>
    operator actual() {
        static_assert(std::is_same_v<expected, actual>);
        return {};
    }
};
auto result = less(int{1}, should_convert_to<int>());
static_assert(std::is_same_v<decltype(result), bool>);

// error: static_assert failed due to requirement 'std::is_same_v<short, int>'
// less(int{1}, should_convert_to<short>()); 
Etienne Laurin
  • 6,731
  • 2
  • 27
  • 31
0

You could use a wrapper class that gives you the signature:

// ...

template <typename, typename, typename = void>
struct less_fptr;

template <typename X, typename Y>
struct less_fptr<X, Y, std::enable_if_t<!std::is_convertible_v<Y, X>>> {
    using type = less_fptr<X, Y>;
};

template <typename X, typename Y>
struct less_fptr<X, Y, std::enable_if_t<std::is_convertible_v<Y, X>>> {
    using type = bool(*)(const X&, const std::type_identity_t<X>&);
};

// ...

static_assert(std::is_same_v<typename less_fptr<decltype(short{1}), decltype(long{2})>::type, typename less_fptr<decltype(short{1}), decltype(double{2})>::type>);
Ruks
  • 3,886
  • 1
  • 10
  • 22