StephenD
StephenD

Reputation: 259

Why can't the compiler deduce my template value from the function argument?

The following won't compile:

enum E {A,B,C};
template<E m> 
void foo(E m) {}

int main() {
    foo(A);
    return 0;
}

The errors I get are:

I don't understand what exactly is wrong here. Why can't the compiler deduce the template parameter from the function argument?

What do I need to do to make this work?

Upvotes: 2

Views: 753

Answers (3)

StephenD
StephenD

Reputation: 259

It has finally dawned on me why this does not compile. Although in my particular case the function argument is a compile-time constant (an enum member), in general a function argument is run-time dependent. The template value must be a compile-time constant, so function argument values are not permissible for template value deduction. If the mechanism for enforcing this is name-hiding, then I think that is incidental. The conclusion is that whereas templated function types may be deduced from function argument type, template values are not deducible.

Upvotes: 0

Daniel Frey
Daniel Frey

Reputation: 56863

If you want a run-time argument, use:

void foo(E m) {}

Which has a value m of type E. (note: no template<E m> required)

If you want a compile-time argument, use:

template<E m> 
void foo() {}

and call:

foo<A>();

Or if you want foo to work for all enumeration types:

template<typename E> 
void foo(E m) {}

And probably check for enums with

static_assert(std::is_enum<E>::value, "E is not an enumeration");

in the function body. (You can also use SFINAE to remove foo from an overload set if needed, ask if you need help with that)


Update: Explaining your original code and what is wrong with it:

template<E m> void foo(E m) {}
//       ^^^ (1)       ^^^ (2)

(1) is a compile-time argument m of type E, (2) is a run-time argument also called m and also of type E. Since it has the same name, the second argument hides the first one. Using the name m in your function will only access the second argument and you can not access the first one. Now consider:

template<E m1> void foo(E m2) {}

Now you can access the arguments under different names, i.e., m1 and m2. If you call the function like this:

foo<A>(B);

then m1 is A and m2 is B. And still both are of the same fixed type E. They are independent parameters and the value of the run-time parameter will not be used for the compile-time parameter.

Depending on which kind or argument you need (compile-time or run-time), you simply leave out the one you don't need and you end up with one of the above implementations.

It's not 100% clear to me where your real problem is, which is not untypical for beginners as it is admittedly hard to describe a problem you don't really understand, but make sure you start by understanding the difference between the compile-time and the run-time parameters and how they can be used.

Upvotes: 6

ISanych
ISanych

Reputation: 22680

I guess you wanted to write:

enum E {A,B,C};
template<typename T> 
void foo(T m) {}

int main() {
    foo(A);
    return 0;
}

Upvotes: 2

Related Questions