8

The question almost does not make sense without an example. So here is what I'm trying to do.

In general C++ allows the following:

template<class T, class U, T t, U u>
void func() {}

func<char, int, 'A', 10>();

But it seems like its natural variadic extension does not work.

template<class...T, T... t>
void func() {}

func<char, int, 'A', 10>(); 

Both clang and g++4.7 reject the above code. The error is shown where the instantiation is done. It appears to me that the two variadic lists should be parsed unambiguously because the first one has types and the other one has integral values only.

If the above is not meant to work, I think the following won't work either.

template <class Ret, class... Args, Ret (*func)(Args...)>
class Foo {};

I think the Foo template is a rather useful thing to have.

Xeo
  • 129,499
  • 52
  • 291
  • 397
Sumant
  • 4,286
  • 1
  • 23
  • 31
  • 2
    The `Foo` template would be like saying `template`, the last template parameter really doesn't add anything at all and is therefore completely unnessecary, afterall the type can be expressed just fine using the template parameters (e.g. `typedef Ret(*func)(Args...)` inside of `Foo`) – Grizzly Jan 12 '12 at 03:49
  • 2
    @Grizzly: The last parameter isn't providing a *type* (which could be replaced by typedef), it's providing a function pointer. A function pointer which is substituted at compile-time, thus enabling cross-procedural optimization such as inlining. – Ben Voigt Jan 12 '12 at 06:02
  • @Sumant: You are right that it seems unambiguous, however I think the Standard simply aimed for simplicity here by specifying that a parameter pack was the last possible "parameter" and nothing could come afterward. This makes matching easier. – Matthieu M. Jan 12 '12 at 07:11
  • @Ben Voigt: Ah you are right of course. Note to self: Shouldn't make such comments in the middle of the night – Grizzly Jan 12 '12 at 14:47

2 Answers2

8

(Extra: Directly answering your first question, you can also turn template<class...T, T... t> void func() {} into a template-inside-a-template. This doesn't work in g++4.6, but does in clang 3.0, hence it took me a while to find it.)

Put a template inside a template:

template<class ... T>
struct func_types {
   template <T ... t>
   static void func_values() {
       // This next line is just a demonstration, and 
       // would need to be changed for other types:
       printf("%c %d\n", t...);
   }
};

int main() {
    func_types<char, int> :: func_values<'A', 10>();
}

Is a template-inside-a-template acceptable? An alternative is to use tuples with func< tuple<char,int> , make_tuple('A',10) >. I think this is doable, but you might have to roll your own tuple class (it appears that make_tuple isn't a constexpr.

Finally, you might be able to implement your Foo template as follows:

template<typename Ret, typename ...Args>
struct Foo {
        template< Ret (*func)(Args...)>
        struct Bar {
                template<typename T...>
                Bar(T&&... args) {
                        cout << "executing the function gives: "
                           << func(std::forward(args)...) << endl;
                }
        };
};

int main () {
    Foo<size_t, const char*> ::  Bar<strlen> test1("hi");
    Foo<int, const char*, const char*> ::  Bar<strcmp> test2("compare","these");
}

This latter code is on ideone. To demonstrate, I implemented a constructor to forward the args to the function that's code into the template.

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • 1
    Note that it's bad to use `Args&&...`, since perfect forwarding is powered by template argument deduction. You specify the argument types explicitly however, as such this is redundant. – Xeo Jan 12 '12 at 05:47
  • Ah yes, @Xeo. I should replace `func(args...)` with `func(std::forward(args...)` as otherwise the rvalues lose their rvalue-ness (assuming our `func` did take rvalues)? That makes sense to me. Is there some other subtlety I'm missing? – Aaron McDaid Jan 12 '12 at 05:59
  • .. oh, actually, I think I also need to make the constructor itself a template, so that it gets this deduction stuff. – Aaron McDaid Jan 12 '12 at 06:03
  • I tried this solution before. The problem is that types in the function's signature must be manually passed to the outer class template. It is not possible to deduce the types from a function pointer and at the same time pass it as a template value parameter. Deduction works only when the function pointer is passed as a regular function parameter. From there it can't become a part of template parameter list. I'll be happy to be proved wrong. – Sumant Jan 12 '12 at 18:36
  • @Sumant, I'm not sure what your goal is. Can you give an example of how you would like to be able to use `Foo`? Do you want to be able to do `typedef Foo f;` and then use `f` to access deduced information about the function strcmp, perhaps `f :: num_args` would be the number of arguments to strlen. Is this what you wanted? (I'm not sure it's possible, but I'm curious as to your ultimate goal) – Aaron McDaid Jan 12 '12 at 20:13
  • @Sumant, I think it is possible to "to deduce the types from a function pointer and at the same time pass it as a template value parameter", if you're prepared to wrap it up in a macro. I think we can get `typedef MAGICAL_MACRO(strlen) t;` to work (where `t` will then have the type I think you want), even if we can't get `typedef GreatTemplate t;` to work. Is this what you are looking for? I've made progress in recent hours on related issues, I enjoy thinking about this! – Aaron McDaid Jan 12 '12 at 22:45
  • @Sumant, Here's a [stripped down version](http://ideone.com/ZZIT7) with that macro I promised. It automatically infers all the types and so on. You might also find [this question and answer](http://stackoverflow.com/questions/8843290/deducing-stdfunction-with-more-than-two-args/8844341#8844341) useful; I asked my own question about deduction. – Aaron McDaid Jan 13 '12 at 14:49
  • @Aaron, Thanks for the answer. Here is how I ended up using it: http://cpptruths.blogspot.com/2012/01/general-purpose-automatic-memoization.html Jump straight to the static_memoizer part. – Sumant Jan 21 '12 at 19:53
  • That's interesing, @Sumant. I recently did a little bit of memoization myself - while writing some C++ code to allow myself to use more of a Haskell style for manipulating lists. Anyway, nice post. Glad to have been of assistance. – Aaron McDaid Jan 21 '12 at 20:58
2

Because noone has thought it would be worth to have this feature. The design of variadic template was intended to be simple and working. Other potentially advanced and useful features werent included either.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212