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?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • You can't do partial specialization with function template. But I think you want to ask something else. Not very clear to me. – Arunmu Jul 19 '16 at 16:36
  • @Arunmu 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? – Jonathan Mee Jul 19 '16 at 16:45
  • 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? – Barry Jul 19 '16 at 16:49
  • 1
    @JonathanMee Yes, better, but I am afraid that the answer remains the same :) – Arunmu Jul 19 '16 at 16:50
  • @Barry 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. – Jonathan Mee Jul 19 '16 at 16:51
  • @Barry You feel like calling that guy brilliant is a bit too far? ;) – Jonathan Mee Jul 19 '16 at 17:08

3 Answers3

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>{}); }
Barry
  • 286,269
  • 29
  • 621
  • 977
  • What's the `tag` for? – Cheers and hth. - Alf Jul 19 '16 at 17:02
  • @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. – Jonathan Mee Jul 19 '16 at 17:07
  • The 2 definitions of `myTry` would be different overloads without `tag`. – Cheers and hth. - Alf Jul 19 '16 at 17:12
  • @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. – Jonathan Mee Jul 19 '16 at 17:16
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;
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 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? – Jonathan Mee Jul 19 '16 at 17:27
  • I've asked a follow up question here: http://stackoverflow.com/q/38482805/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. – Jonathan Mee Jul 20 '16 at 13:42
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;
}
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • 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](http://stackoverflow.com/questions/38463980/pull-apart-function-type-with-specialized-function#comment64332056_38463980). Maybe instead of this you could just quote something official sounding that specifies that functions cannot be specialized? – Jonathan Mee Jul 19 '16 at 16:48
  • I don't see what there is to gain from replacing the struct. It takes up exactly 0 bits, once it's compiled. – Sam Varshavchik Jul 19 '16 at 16:49
  • 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." – Jonathan Mee Jul 19 '16 at 16:53
  • 1
    @JonathanMee: Functions can be completely specialized, but not partially specialized. – Cheers and hth. - Alf Jul 19 '16 at 17:04
  • 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). – acwaters Jul 19 '16 at 17:15