How to use a template parameter in another template parameter declared before
Asked Answered
I

4

7

a template parameter can be used in another template parameter that follows it this way :

template<typename T, T N>
struct s
{
};

But is it possible to reference "T" if it is declared after "N" ?

This does not work :

template<T N, typename T>
struct s
{
};

Can we help the compiler by pre-declaring "T" or doing anything else ?

Thanks by advance.

EDIT : as the first two replies were asking "why are you willing to do that ?" I'll explain the goal :

I would like to make the compiler infer the type "T" in order to make the use of templated classes easier.

For example :

template<typename T, T A, T B>
struct sum
{
    static T const value = A + B;
};

This template can be used this way :

sum<int, 1, 2>::value

But it would be better if it could be used this way :

sum<1, 2>::value

Technically it's should be possible because the compiler knows the types of "1" and "2" : "int", and in fact it uses these informations to find the best overload for a function. So by declaring the template this way :

template<T A, T B, typename T>
struct sum
{
    static T const value = A + B;
};

the compiler could use its capability to infer the last parameter from the informations provided by the first and the second one, and then find the best template to instantiate.

Influx answered 18/9, 2009 at 22:48 Comment(0)
S
8

Like others say - No this isn't possible, the compiler can't infer the type of T from the non-type template arguments (in the case of functions, it infers types from the function arguments):

14.8.2.4/12:

A template type argument cannot be deduced from the type of a non-type template-argument.

In any case, no deduction will be made for the arguments of a class template anyway. An example for a function template might be

template<int> struct having_int { };
template<typename T, T i> void f(having_int<i>);
int main() { having_int<0> h; f(h); }

In this case, T won't be deduced as int - you have to explicitly specify it.

Sikko answered 19/9, 2009 at 0:45 Comment(2)
Thanks for the answer : if the norm says no it's no. The question is now : why this limited behavior whereas it seems possible to do this deduction ? Do you have some examples justifying this decision ? Thanks.Influx
Because template metaprogramming was never meant to be expressive? :) Interesting question, though. May-be you should check whether this has been proposed, or make that proposition for C++1x.Agni
P
0

You can't. I don't see the point why you are doing it too.

Polio answered 18/9, 2009 at 22:50 Comment(1)
This is not an answer. Consider leaving a comment on the original question.Afford
A
0

Below is rubbish as I didn't read your question properly.

Indeed, I don't see any point in what you are trying to achieve either.

#include <iostream>

template<typename T, T N>
struct s
{
    T size() { return N; }
};


int main()
{
    s<int, 4> x;
    std::cout << x.size()<< '\n';

    //s<float, 3.14> f; //this doesn't compile
}

This compiles for me with GCC and Comeau Online.

I think the problem is with the type of T you are trying to use. Non-type template arguments only support integral types, and then pointers to objects with external linkage (or something like that and perhaps a few other very limited things).

Agni answered 18/9, 2009 at 22:54 Comment(0)
I
0

You can do this with C++17

template <auto n>
struct s;

template <typename T, T n>
struct s<n>
{
    static constexpr T threshold = n;
    bool above_threshold(T x) { return x > threshold; }
};

and then you'll be able to do

void some_fn(int x)
{
    s<18> my_s;
    if (my_s.above_threshold(x)) { /*...*/ }
}
Insuppressible answered 18/7 at 16:40 Comment(1)
How would you apply it to the original use case: ``` #include <iostream> template<typename T, T A, T B> struct sum { static T const value = A + B; }; int main() { std::cout << sum<int, 1, 2>::value << std::endl; } ``` ?Influx

© 2022 - 2024 — McMap. All rights reserved.