decltype of function parameter [duplicate] - c++

This question already has answers here:
How is possible to deduce function argument type in C++?
(4 answers)
Closed 1 year ago.
Is it possible to deduce the type of a function parameter? For example, if I have:
void foo(int a);
I would like to deduce the type int as the type of foo's first parameter. A possible use could be:
foo( static_cast< decltype(/* ??? foo's first param ??? */) >(value) );
In this related question, the answers exploit having a member with the same type for deduction, so it does not directly deduce the function parameter type.

Is it possible to deduce the type of a function parameter?
Sure.
With a type traits, by example (argType)
template <typename>
struct argType;
template <typename R, typename A>
struct argType<R(A)>
{ using type = A; };
void foo(int a)
{ }
int main()
{
long value = 1L;
foo( static_cast<typename argType<decltype(foo)>::type>(value) );
}
If you're interrested in a little more generic solution, the following example show how create and use a type traits to detect the return type or the n-th argument type
#include <string>
template <std::size_t N, typename T0, typename ... Ts>
struct typeN
{ using type = typename typeN<N-1U, Ts...>::type; };
template <typename T0, typename ... Ts>
struct typeN<0U, T0, Ts...>
{ using type = T0; };
template <std::size_t, typename>
struct argN;
template <std::size_t N, typename R, typename ... As>
struct argN<N, R(As...)>
{ using type = typename typeN<N, As...>::type; };
template <typename>
struct returnType;
template <typename R, typename ... As>
struct returnType<R(As...)>
{ using type = R; };
long bar (int a, std::string const &)
{ return a; }
int main()
{
long valI = 1L;
char const * valS = "abc";
bar( static_cast<typename argN<0U, decltype(bar)>::type>(valI),
static_cast<typename argN<1U, decltype(bar)>::type>(valS) );
static_assert(
std::is_same<long,
typename returnType<decltype(bar)>::type>::value, "!");
}

A slightly generalized version of the answer by #max66:
template <typename> struct FirstArgument;
template <typename R, typename A, typename... Args>
struct FirstArgument<R(A, Args...)>
{
using type = A;
};
template <typename T>
using first_agument_t = typename FirstArgument<T>::type;
void foo(int a){ }
void bar(int a, double b){ }
int main()
{
long value = 1L;
foo(static_cast<first_agument_t<decltype(foo)>>(value) );
bar(static_cast<first_agument_t<decltype(bar)>>(value), 0);
}

Related

Is it possible to call a function with all arguments default constructed?

Is it possible to have a function like std::invoke, but this function calls all arguments of the given function automatically with the default constructed types?
#include <iostream>
#include <functional>
// e.g. for a single arg
struct Test{
void operator()(int i) {
std::cout << std::to_string(i) << "\n";
}
};
int main(){
Test test;
std::invoke(test, {}); // this doesn't work, would like it to call with default constructed int (0).
return 0;
}
I would like something like
int main()
{
Test test;
invoke_with_defaults(test); // prints 0
return 0;
}
You need a class with a templated conversion operator, returning {} for any type:
struct DefaultConstruct
{
DefaultConstruct() = default;
DefaultConstruct(const DefaultConstruct &) = delete;
DefaultConstruct &operator=(const DefaultConstruct &) = delete;
template <typename T> operator T() && {return {};}
};
int main()
{
Test test;
std::invoke(test, DefaultConstruct{});
}
It's then possible to write a template that automatically determines how many of those have to be passed:
template <typename F, typename ...P>
decltype(auto) InvokeDefault(F &&func)
{
if constexpr (std::is_invocable_v<F, P...>)
return std::invoke(std::forward<F>(func), P{}...);
else
return InvokeDefault<F, P..., DefaultConstruct>(std::forward<F>(func));
}
int main()
{
Test test;
InvokeDefault(test);
}
And if the argument isn't callable at all, you get a compilation error after exceeding some implementation-defined limit (on Clang I got up to 256).
Initializer lists like {} cannot be forwarded as a parameter due not work due to language restrictions.
But you can mimick {} by wrapping it into a Defaulter class which can be passed around:
#include <iostream>
#include <functional>
// e.g. for a single arg
struct Test{
void operator()(int i) {
std::cout << std::to_string(i) << "\n";
}
};
struct Defaulter{
template<typename T>
operator T(){
return {};
}
};
int main(){
Test test;
std::invoke(test, Defaulter{});
return 0;
}
You could use something like this to create a tuple of all of the argument types, and then pass a default constructed instance of it to std::apply. The specialisation list would need to be quite long though to cover all of the const, volatile, noexcept, and ref-qualified variants though, and of course it cannot work with template or overloaded functions.
Eg:
template <typename T>
struct arg_extractor : arg_extractor<decltype(&T::operator())> {
};
template <typename R, typename... Args>
struct arg_extractor<R (*)(Args...)> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...)> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) const> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) noexcept> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) const noexcept> {
using type = std::tuple<R, Args...>;
};
// All the rest...
template <typename T>
using arg_extractor_t = typename arg_extractor<T>::type;

Partial specialization does not use any of its template parameters

I'm trying to implement tuples with template metaprogramming, but am having problems with the indexing function get. The implementation of Tuple type is this:
template<typename A, typename... B>
class Tuple : Tuple<B...> {
private:
A val;
public:
using Base = Tuple<B...>;
Base* base() {
return static_cast<Base*>(this);
}
const Base* base() const {
return static_cast<const Base*>(this);
}
Tuple(A a, B... b): Base(b...), val(a) { }
A first() {
return val;
}
};
template<class A>
class Tuple<A> {
private:
A val;
public:
Tuple(A a): val{a} {}
A first() {
return val;
}
};
The implementation of get structure is:
template<int N, class... A>
struct get {
select<N,A...> operator()(Tuple<A...> t) {
return get<N-1>()(t.base());
}
};
template<class R, class... A>
struct get<0> {
R operator()(Tuple<R, A...> t) {
return t.first();
}
};
This is the error compiler is giving me:
tuple.cpp:53:8: error: partial specialization of 'get' does not use any of its template parameters
struct get<0> {
^
1 error generated.
Why am I getting this error? How can I correct it?
Note: select<N,A...> is a type function which selects type at Nth index from A.
Your get's primary template is:
template<int N, class... A>
struct get{ ... };
your get's partial specialization is:
template<class R, class... A>
struct get<0>{ ... };
The specialization is receiving a single template argument, i.e.: 0, but the primary template above takes two template parameters:
the non-type template parameter N.
the variadic type parameter A.
Besides, how can R be deduced?
Specializing get instead as:
template<class R, class... A>
struct get<0, R, A...>{ ... };
will make possible R to be deduced: it will be deduced to the type of the first element of the passed variadic argument. For example, in:
get<0, int, float, double> foo;
R will be deduced to int.
Maybe you have to partial specialize get as follows
template<class R, class... A>
struct get<0, R, A...> {
R operator()(Tuple<R, A...> t) {
return t.first();
}
};
I mean... get<0, R, A...>, not get<0>
But you have also to modify the main get to call the following call with the correct type list, so
template<int N, typename A0, typename ... As>
struct get {
auto operator()(Tuple<A0, As...> t) {
return get<N-1, As...>()(t.base());
}
};
Otherwise you can also demand the types management to a template version of the operator() and maintain only the int N value for get
template <int N>
struct get
{
template <typename Tpl>
auto operator() (Tpl t)
-> decltype( get<N-1>()(t.base()) )
{ return get<N-1>()(t.base()); }
};
template<>
struct get<0>
{
template <typename Tpl>
auto operator() (Tpl t)
-> decltype ( t.first() )
{ return t.first(); }
};
Starting from C++14 you can avoid the decltype() part.
Off topic suggestion: avoid the use of names that can collide with std namespace names.
Maybe myGet and myTuple instead of get and Tuple.
Otherwise you can put all in a personal namespace (so myNs::get and myNs::Tuple.

Expand a type N times in template parameter

I have the following problem:
template< std::size_t N >
class A
{
std::function< std::size_t( /*std::size_t,....,std::size_t <- N-times*/) > foo;
};
As you can see above, I try to declare an std::function<...> foo as a member of a class A. Here, I want foo to have the return type std::size_t (which is no problem) and as input, I will pass N-times the type std::size_t but I don't know how. Is there any possibility?
Many thanks in advance.
You can use std::index_sequence:
template<std::size_t N, typename = std::make_index_sequence<N>>
struct A;
template<std::size_t N, std::size_t... S>
struct A<N, std::index_sequence<S...>> {
std::function<std::size_t(decltype(S)...)> foo;
};
Live example
If you like, you could also define to what type it expands:
template<typename T, std::size_t N, typename = std::make_index_sequence<N>>
struct A;
template<typename T, std::size_t N, std::size_t... S>
struct A<T, N, std::index_sequence<S...>> {
template<std::size_t>
using type = T;
std::function<std::size_t(type<S>...)> foo;
};
For arbitrary type and not just size_t, just write a helper alias:
template<class T, size_t>
using Type = T;
template<std::size_t... S>
struct AHelper<std::index_sequence<S...>> {
std::function<size_t(Type<MyArbitraryTypeHere, S>...)> foo;
};
Ok this was fun. Here is my solution:
namespace details {
template <size_t N, class F = size_t()>
struct Function_type_helper {};
template <size_t N, class... Args>
struct Function_type_helper<N, size_t(Args...)> {
using Type = typename Function_type_helper<N - 1, size_t(Args..., size_t)>::Type;
};
template <class... Args>
struct Function_type_helper<0, size_t(Args...)> {
using Type = size_t(Args...);
};
template <size_t N, class F = size_t()>
using Function_type_helper_t = typename Function_type_helper<N, F>::Type;
static_assert(std::is_same_v<Function_type_helper_t<3>, size_t(size_t, size_t, size_t)>);
} // ns details
template<size_t N>
struct A
{
std::function<details::Function_type_helper_t<N>> foo;
};
This works by recursively creating the type size_t(size_t, size_t, ..., size_t)
For instance:
H<3>::Type == H<3, size_t()>::Type ==
H<2, size_t(size_t)>::Type ==
H<1, size_t(size_t, size_t)>::Type ==
H<0, size_t(size_t, size_t, size_t)>::Type ==
size_t(size_t, size_t, size_t)

How to deduce C++ return type in template?

I have a functor, I want the return type to be deduced automatically. How can I do this?
template <typename _ScalarL, typename _ScalarR>
struct Multi
{
DEDUCEDTYPE operator()(_ScalarL input1, _ScalarR input2) const
{
return input1 * input2;
}
};
int main(){
Multi<int, double> mt;
mt(1,2.0);
}
how to get the DEDUCEDTYPE automatically?
how to get the DEDUCEDTYPE automatically [with c++03]?
Automatic type deduction is not possible with C++03. As mentioned in other answer, you may have to manually create your own deducing specializations.
For C++11/C++14:
// For C++14, simply `auto` is enough
auto operator()(_ScalarL input1, _ScalarR input2) const
#if __cplusplus < 201402L
-> decltype(input1 * input2) // required for C++11
#endif
Well I believe that before c++11 you are doomed to provide deduction by hand... You could create helper struct with specializations for that:
template <typename A, typename B>
struct deduce { };
template <>
struct deduce<int, double> {
typedef double type;
};
template <typename ScalarL, typename ScalarR>
struct Multi
{
typename deduce<ScalarL, ScalarR>::type operator()(ScalarL input1, ScalarR input2) const
{
return input1 * input2;
}
};
int main(){
Multi<int, double> mt;
mt(1,2.0);
}
Edit:
The more general way of doing it would invoke however creating the hierarchy of priorities of the types that should be considered while deducing result type. Exemplary code:
#include <iostream>
template <typename T>
struct MoreGeneralNumber { };
template <>
struct MoreGeneralNumber<long>: MoreGeneralNumber<int> {};
template <>
struct MoreGeneralNumber<float>: MoreGeneralNumber<long> {};
template <>
struct MoreGeneralNumber<double>: MoreGeneralNumber<float> {};
typedef char (&yes)[1];
typedef char (&no)[2];
template <bool L, bool R, typename LT, typename RT>
struct MoreGeneral { };
template <bool R, typename LT, typename RT>
struct MoreGeneral<true, R, LT, RT> {
typedef LT type;
};
template <typename LT, typename RT>
struct MoreGeneral<false, true, LT, RT> {
typedef RT type;
};
template <typename B, typename D>
struct Host
{
operator B*() const;
operator D*();
};
template <typename B, typename D>
struct is_base_of
{
template <typename T>
static yes check(D*, T);
static no check(B*, int);
static const bool value = sizeof(check(Host<B,D>(), int())) == sizeof(yes);
};
template <typename L, typename R>
struct Deduce: MoreGeneral<is_base_of<MoreGeneralNumber<R>, MoreGeneralNumber<L> >::value,
is_base_of<MoreGeneralNumber<L>, MoreGeneralNumber<R> >::value, L, R > {
};
template <typename ScalarL, typename ScalarR>
struct Multi
{
typename Deduce<ScalarL, ScalarR>::type operator()(ScalarL input1, ScalarR input2) const
{
return input1 * input2;
}
};
int main() {
Multi<int, double> mt;
std::cout << mt(1, 2.5) << std::endl;
}

Mimic std::function template arguments

I'm want to mimic std::function template arguments but I don't know how it really works.
Consider this code for example:
std::function<int(int)> p;
How do I write class template that mimics this template parameter <int(int)> ?
template<typename ...> <-- what should be here instead of `...`
MyClass
What I'm really trying to achieve is that I want to be able to typedef <int(int)> as function pointer and I want it to be generic not only for int (*func)(int) functions.
I'm trying to achieve something like this:
SomeSmartStruct<MyClass, int(int)>::MemFuncPointerType pMemFunc;
I want MemFuncPointerType to be of the following type:
int (__thiscall MyClass::* )(int)
And:
SomeSmartStruct<MyClass, int(int)>::FunctionPointer pFunc;
should be of this type:
int (__cdecl *)(int)
I'm using VS2010 so not all C++11 features are supported but it does implements std::function.
With variadic templates:
template <typename C, typename T>
struct make_member_function_pointer;
template <typename C, typename R, typename... Args>
struct make_member_function_pointer<C,R(Args...)>
{
using type = R(C::*)(Args...);
};
DEMO 1
Without variadic templates:
template <typename T> struct identity { typedef T type; };
template <typename C, typename T>
struct make_member_function_pointer;
template <typename C, typename R, typename Arg1>
struct make_member_function_pointer<C,R(Arg1)> : identity<R(C::*)(Arg1)> {};
template <typename C, typename R, typename Arg1, typename Arg2>
struct make_member_function_pointer<C,R(Arg1,Arg2)> : identity<R(C::*)(Arg1,Arg2)> {};
template <typename C, typename R, typename Arg1, typename Arg2, typename Arg3>
struct make_member_function_pointer<C,R(Arg1,Arg2,Arg3)> : identity<R(C::*)(Arg1,Arg2,Arg3)> {};
DEMO 2
Usage:
template <typename T, typename F>
struct SomeSmartStruct
{
typedef typename make_member_function_pointer<T,F>::type MemFuncPointerType;
typedef F* FunctionPointer;
};
Tests:
struct MyClass
{
int foo(int) {return 0;}
};
int bar(int) {return 0;}
int main()
{
SomeSmartStruct<MyClass, int(int)>::MemFuncPointerType pMemFunc = &MyClass::foo;
SomeSmartStruct<MyClass, int(int)>::FunctionPointer pFunc = &bar;
}
UPDATE
Can I somehow utilize the preprocessor to auto generate partial specializations of make_member_function_pointer? I've seen something similar is done using BOOST_PP_ITERATION but I don't know how it works.
Sure:
#include <boost/preprocessor.hpp>
template <typename T> struct identity { typedef T type; };
template <typename C, typename T>
struct make_member_function_pointer;
#define BOOST_PP_LOCAL_MACRO(n)\
template <typename C, typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Arg)>\
struct make_member_function_pointer<C,R(BOOST_PP_ENUM_PARAMS(n, Arg))> : identity<R(C::*)(BOOST_PP_ENUM_PARAMS(n, Arg))> {};
#define BOOST_PP_LOCAL_LIMITS (0, 20) // 20 is the limit of params
#include BOOST_PP_LOCAL_ITERATE()
Tests:
int bar10(int,int,int,int,int,int,int,int,int,int) {return 0;}
SomeSmartStruct<MyClass, int(int,int,int,int,int,int,int,int,int,int)>::FunctionPointer pFunc10 = &bar10;
DEMO 3
int(int) is just a type so can be matched by template <typename T>.
Surely too generic:
template<typename T>
struct Pointer
{
typedef T* type;
};
And then you may do
int foo(int i) {return i;}
int main() {
Pointer<int(int)>::type f = &foo;
}