I am trying to write a generic wrapper for building out a Python function from a C++ driver. To start I want to be able to just use some template magic to be able to generate the associated ctypes
and be able to print them. I have everything sort of working, but I cannot seem to pull the function signature types a layer up, which defeats the purpose...
I currently have the following minimal reproduction of the issue, also on godbolt:
#include <functional>
#include <iostream>
template <typename T>
struct ctype
{
using type = void*;
static constexpr char name[] = "c_void_p";
};
template <>
struct ctype<int>
{
static constexpr char name[] = "c_int";
};
template <>
struct ctype<double>
{
static constexpr char name[] = "c_double";
};
template<typename T>
struct function_traits;
template<typename R, typename ...Args>
struct function_traits<std::function<R(Args...)>>
{
static constexpr size_t nargs = sizeof...(Args);
using result_ctype = ctype<R>;
template <size_t i>
using arg_ctype = ctype<typename std::tuple_element<i, std::tuple<Args...>>::type>;
};
template <typename FuncSignature>
void log_function_signature()
{
// using function_proto = function_traits<std::function<double(double,int)>>; // OK
using function_proto = function_traits<std::function<FuncSignature>>; // BAD? Why?
std::cout << function_proto::result_ctype::name << std::endl;
std::cout << function_proto::arg_ctype<0>::name << std::endl;
std::cout << function_proto::arg_ctype<1>::name << std::endl;
}
double foobar(double x, int y)
{
return x * y;
}
int main() {
log_function_signature<double(double,int)>();
}
The function_traits
was adapted from this answer: https://stackoverflow.com/a/9065203/2242096. Ideally I would just use FuncSignature
directly inside of log_function_signature
, but I cannot figure out why this is not allowed. The compiler gives me the following:
<source>: In function 'void log_function_signature()':
<source>:42:48: error: '::name' has not been declared; did you mean 'rename'?
42 | std::cout << function_proto::arg_ctype<0>::name << std::endl;
| ^~~~
| rename
<source>:43:48: error: '::name' has not been declared; did you mean 'rename'?
43 | std::cout << function_proto::arg_ctype<1>::name << std::endl;
| ^~~~
| rename
<source>: In instantiation of 'void log_function_signature() [with FuncSignature = double(double, int)]':
<source>:52:48: required from here
<source>:42:34: error: dependent-name 'function_proto::arg_ctype' is parsed as a non-type, but instantiation yields a type
42 | std::cout << function_proto::arg_ctype<0>::name << std::endl;
| ^~~~~~~~~
<source>:42:34: note: say 'typename function_proto::arg_ctype' if a type is meant
<source>:43:34: error: dependent-name 'function_proto::arg_ctype' is parsed as a non-type, but instantiation yields a type
43 | std::cout << function_proto::arg_ctype<1>::name << std::endl;
| ^~~~~~~~~
<source>:43:34: note: say 'typename function_proto::arg_ctype' if a type is meant
ASM generation compiler returned: 1
<source>: In function 'void log_function_signature()':
<source>:42:48: error: '::name' has not been declared; did you mean 'rename'?
42 | std::cout << function_proto::arg_ctype<0>::name << std::endl;
| ^~~~
| rename
<source>:43:48: error: '::name' has not been declared; did you mean 'rename'?
43 | std::cout << function_proto::arg_ctype<1>::name << std::endl;
| ^~~~
| rename
<source>: In instantiation of 'void log_function_signature() [with FuncSignature = double(double, int)]':
<source>:52:48: required from here
<source>:42:34: error: dependent-name 'function_proto::arg_ctype' is parsed as a non-type, but instantiation yields a type
42 | std::cout << function_proto::arg_ctype<0>::name << std::endl;
| ^~~~~~~~~
<source>:42:34: note: say 'typename function_proto::arg_ctype' if a type is meant
<source>:43:34: error: dependent-name 'function_proto::arg_ctype' is parsed as a non-type, but instantiation yields a type
43 | std::cout << function_proto::arg_ctype<1>::name << std::endl;
| ^~~~~~~~~
<source>:43:34: note: say 'typename function_proto::arg_ctype' if a type is meant
Execution build compiler returned: 1
Why does the template type work when written inside of the function, but not when passed in through a template?