Pull Apart Function Type With Specialized Function
Asked Answered
C

3

2

The answer to this question picks apart a function type using a class template:

template <typename T>
struct function_args {};

template <typename R, typename... Args>
struct function_args<R(Args...)> {
    using type = tuple<Args...>;
};

template <typename T>
using decltypeargs = typename function_args<T>::type;

As I studied what was being done here I tried to rewrite function_args. I attempted to do this using a function so as to eliminate the need for the decltypeargs template. But found myself mired in improper syntax:

template <typename T>
tuple<> myTry();

template <typename Ret, typename... Args>
tuple<Args...> myTry<Ret(Args...)>();

My hope had been to call decltype(myTry<decltype(foo)>()) to get the tuple type instead of having to call decltypeargs<decltype(foo)>. Is there a way to do this with a function declaration?

Cchaddie answered 19/7, 2016 at 16:30 Comment(6)
You can't do partial specialization with function template. But I think you want to ask something else. Not very clear to me.Longshoreman
@Longshoreman Sounds like you've answered my question. But I'm not certain how to improve the wording. I'm trying to pull a function's return and arguments apart, and I need to use specialization to do that. I wanted to do it with a function, but it sounds like I can't. Is that any clearer?Cchaddie
Not sure what you're trying to do. myTry() is just more typing than not using it - what's the problem you're trying to solve?Maltreat
@JonathanMee Yes, better, but I am afraid that the answer remains the same :)Longshoreman
@Maltreat I was just trying to rewrite your answer in terms that made more sense to me (function declarations.) But it seems that function declarations cannot be specialized like this. So I just need to get more comfortable with specializing objects.Cchaddie
@Maltreat You feel like calling that guy brilliant is a bit too far? ;)Cchaddie
C
2
//------------------------ Machinery:
#include <tuple>

template< class Ret, class... Args >
std::tuple<Args...> m( Ret(Args...) );

//------------------------- Example:
#include <iostream>
#include <typeinfo>

void foo( double );

using namespace std;
auto main()
    -> int
{
    using Args_tuple = decltype( m( foo ) );
    cout << typeid( Args_tuple ).name() << endl;
}
Centare answered 19/7, 2016 at 17:21 Comment(2)
Ugh. That's exactly what I couldn't put together how to do, right there in one function. Who needs specialization when you can do it right the first time?Cchaddie
I've asked a follow up question here: https://mcmap.net/q/1633944/-how-can-i-pass-an-undefined-method-like-an-undefined-function/2642059 I think I must not have a good grip on how decltype(m(foo)) is working cause I can't expand it to work with methods.Cchaddie
M
3

With a function, you can either just reuse the same type trait from before:

template <typename T>
function_args<T> myTry();

Or you can reimplement the same with functions. You can't partially specialize function templates, but you can overload:

namespace detail {
    template <class T> struct tag { };

    template <class R, class... Args>
    tag<std::tuple<R, Args...>> myTry(tag<R(Args...)> );

    template <class R, class C, class... Args>
    tag<std::tuple<R, Args...>> myTry(tag<R(C::*)(Args...)> );        

    // etc.
}

template <typename T>
auto myTry() { return detail::myTry(detail::tag<T>{}); }
Maltreat answered 19/7, 2016 at 16:54 Comment(4)
What's the tag for?Centare
@Cheersandhth.-Alf That's what he's using to hack in partial specialization. Fundamentally this is my bad question, obviously the right answer is just use the struct, this is just a creative workaround.Cchaddie
The 2 definitions of myTry would be different overloads without tag.Centare
@Cheersandhth.-Alf Yes, but the interest from the linked question is in extracting the argument types. tag allows us to do that within the context of a functions parameters. If you can think of a better way to do that within a function, I'd say you've come up with a better solution and should post it as an answer.Cchaddie
C
2
//------------------------ Machinery:
#include <tuple>

template< class Ret, class... Args >
std::tuple<Args...> m( Ret(Args...) );

//------------------------- Example:
#include <iostream>
#include <typeinfo>

void foo( double );

using namespace std;
auto main()
    -> int
{
    using Args_tuple = decltype( m( foo ) );
    cout << typeid( Args_tuple ).name() << endl;
}
Centare answered 19/7, 2016 at 17:21 Comment(2)
Ugh. That's exactly what I couldn't put together how to do, right there in one function. Who needs specialization when you can do it right the first time?Cchaddie
I've asked a follow up question here: https://mcmap.net/q/1633944/-how-can-i-pass-an-undefined-method-like-an-undefined-function/2642059 I think I must not have a good grip on how decltype(m(foo)) is working cause I can't expand it to work with methods.Cchaddie
H
1

Functions cannot be specialized like that, but you don't need to specialize a function for this. Tested with gcc 6.1.1:

#include <iostream>
#include <tuple>

template <typename T> struct my_try;

template <typename Ret, typename... Args>
struct my_try<Ret(Args...)> {

    std::tuple<Args...> operator()();

};

template<typename T>
auto MyTry()
{
    return my_try<T>()();
}


void foo(int, char);

int main()
{
    decltype(MyTry<decltype(foo)>()) t;

    int *a= &std::get<0>(t);
    char *b= &std::get<1>(t);

    return 0;
}
Highspeed answered 19/7, 2016 at 16:45 Comment(5)
Haha, I suppose that does accomplish it in a function. I was hoping to replace the struct with a function though. It sounds as though that's not possible though. Maybe instead of this you could just quote something official sounding that specifies that functions cannot be specialized?Cchaddie
I don't see what there is to gain from replacing the struct. It takes up exactly 0 bits, once it's compiled.Highspeed
You're completely right. I just felt more comfortable with function declarations, so I was trying to use them. So the answer, is simply: "You can't do that." But it would be nice if we could get a quote in here citing something other than "Because I said so."Cchaddie
@JonathanMee: Functions can be completely specialized, but not partially specialized.Centare
It's difficult to provide a quote from the Standard for this, because it does not really say anywhere that function templates cannot be partially specialized; it just doesn't say that they can be (whereas it has subsection 14.5.5 specifically devoted to class template partial specialization, this is distinct from subsection 14.7.3 and section 14.8 which talk about explicit template specialization).Acerbic

© 2022 - 2024 — McMap. All rights reserved.