patterncppMinor
Insane template metaprogramming madness
Viewed 0 times
madnessinsanetemplatemetaprogramming
Problem
Given any callable, deduces the first parameter in the parameter list of the function. Be ware, not for light hearted.
Some tests:
After about two weeks of intense Java, I started missing C++. Especially templates.
Motivation:
I'm writing generic sliding window, which is complete, but I don't want to show it yet (I figured that it is possible to do stunning things with it). To supplement it, I need preprocessing iterator, which applies a user supplied functor before assigning to underlying iterator. To make the preprocessing iterator easy to use I need to deduce the first parameter's type to put into
template
struct pick_first;
template
struct pick_first
{
using type = T;
};
template
using pick_first_t = typename pick_first::type;
template
struct deduce_first_parameter
{
private:
template typename Operation>
struct extract_function;
template typename Operation>
struct extract_function
{
using type = typename Operation::type;
};
template typename Operation>
struct extract_function
{
using type = typename Operation::type;
};
template typename Operation>
using extract_function_t = typename extract_function::type;
public:
using type = extract_function_t;
};
template
struct deduce_first_parameter
{
using type = pick_first_t;
};Some tests:
#include
#include
struct dummy
{
void operator()(std::vector&) {}
using correct_answer = std::vector&;
};
struct not_so_dummy
{
using correct_answer = const std::vector>&;
void operator()(const std::vector>&) {}
};
void f(char, int);
int main()
{
static_assert(std::is_same::type, char>::value);
static_assert(std::is_same::type, dummy::correct_answer >::value);
static_assert(std::is_same::type, not_so_dummy::correct_answer>::value);
}After about two weeks of intense Java, I started missing C++. Especially templates.
Motivation:
I'm writing generic sliding window, which is complete, but I don't want to show it yet (I figured that it is possible to do stunning things with it). To supplement it, I need preprocessing iterator, which applies a user supplied functor before assigning to underlying iterator. To make the preprocessing iterator easy to use I need to deduce the first parameter's type to put into
std::iterator<> (I know its deprecated, but some compilers still use it to detect iterators), because binding users to what underlying iterator can accept is awkward.Solution
You can figure out the first parameter of a non-overloaded function pointer pretty easily; I'm not sure but your code looks more complicated than it ought to be.
Unfortunately, your code completely falls down in the presence of overloads and/or templates. Here's the error message:
and here are some types that trigger it:
And here's another error message that I get:
with this input:
If I were tackling this problem, I would first ask myself what "the type of the first parameter" even means in C++, given that we have function overloading and templates. But then I might try to detect the appropriate type by messing around with
and then inspecting
In the cases where overloading and/or templates rendered the question meaningless, I would try to at least give a nice
Unfortunately, your code completely falls down in the presence of overloads and/or templates. Here's the error message:
prog.cc:36:46: error: reference to overloaded function could not be resolved; did you mean to call it?
using type = extract_function_t;
^~~~~~~~~~~~~~~~~~~~~and here are some types that trigger it:
struct oops1 {
void operator()(int);
void operator()(double);
};
struct oops2 {
void operator()(int);
void operator()(int) const;
};
void oops3(int);
void oops3(double);
struct oops4
{
using correct_answer = const std::vector>&;
template>>, int> = 0>
void operator()(T&) {}
};And here's another error message that I get:
prog.cc:11:1: error: implicit instantiation of undefined template 'pick_first<>'
using pick_first_t = typename pick_first::type;
^with this input:
void oops5(void);If I were tackling this problem, I would first ask myself what "the type of the first parameter" even means in C++, given that we have function overloading and templates. But then I might try to detect the appropriate type by messing around with
struct ConvertibleToAnything {
template operator T() const;
};and then inspecting
f(ConvertibleToAnything{}) and trying to figure out which operator T was getting instantiated.In the cases where overloading and/or templates rendered the question meaningless, I would try to at least give a nice
static_assert error message, if not actually produce a tag type so that is_same_v, signature_is_ambiguous_t>.Code Snippets
prog.cc:36:46: error: reference to overloaded function could not be resolved; did you mean to call it?
using type = extract_function_t<decltype(&Callable::operator()), pick_first>;
^~~~~~~~~~~~~~~~~~~~~struct oops1 {
void operator()(int);
void operator()(double);
};
struct oops2 {
void operator()(int);
void operator()(int) const;
};
void oops3(int);
void oops3(double);
struct oops4
{
using correct_answer = const std::vector<std::map<int, char>>&;
template<class T, std::enable_if_t<std::is_same_v<T, const std::vector<std::map<int, char>>>, int> = 0>
void operator()(T&) {}
};prog.cc:11:1: error: implicit instantiation of undefined template 'pick_first<>'
using pick_first_t = typename pick_first<Args...>::type;
^void oops5(void);struct ConvertibleToAnything {
template<class T> operator T() const;
};Context
StackExchange Code Review Q#155647, answer score: 4
Revisions (0)
No revisions yet.