By milanHrabos


2020-08-01 12:01:57 8 Comments

If I do not use tempate parameter (type) in a function argument list -> only as return type, then there is no deduction:

template <typename T>
T zero() { return 0; }

int main()
{
    int x = zero();
}

gives:

a.cpp:15:18: error: no matching function for call to ‘zero()’
     int x = zero();
                  ^
a.cpp:11:3: note: candidate: ‘template<class T> T zero()’
 T zero() { return 0; }
   ^~~~
a.cpp:11:3: note:   template argument deduction/substitution failed:
a.cpp:15:18: note:   couldn't deduce template parameter ‘T’
     int x = zero();

The only way to compile, is to specify the template type in angle brackets:

template <typename T>
T zero() { return 0; }

int main()
{
    int x = zero<int>();
}
  1. So my question is, why g++ can deduce the type from argument list of template function, but cannot deduce it from return type (which is also known for compiler when compiling main, so it knows the type).

  2. providing the type in angle brackets for template function is then arbitrary (because of deduction), when the template function uses template types in its argument list? So as a good practise, should I always provided the type in curly braces, no matter how the function is declared?

The second question is not readable much. Put it in simple words -> should I use foo<T>(arg, ...) (provide the type) everytime, no matter the function declaration? Even if it can be deduced by the compiler, but I will provided the type anyway for good practise?

4 comments

@Phil1970 2020-08-01 13:15:39

Question 1

While it might be relatively easy to modify rules in yout trivial cases, this is not the case generally.

Consider a case like that:

template <A, B, C> A f(B b, C c) { ... } // #1
int f(int a, int b) { ... } // #2
int f(int a, double b) { ... } // #3

And a call like that:

double x = f(1, 2.0);  // Call #1 or #3?

Thus it is not always trivial to modify rules and ensure that existing code continue to works. Such changes could easily lead to ambiguities, silent change of function being called...

Standard usually avoid modifying language in a way that could make unexpected silent changes (or make legal code become ambiguous).

However, it could be nice if there was a way to specify that we want deduction for return type in specific cases. By using a contextual keyword, rules could be defined on how to handled cases like the above one. For example, it could be a conflict if using return type deduction prefer an overload that is not the same one as without return type deduction.

Question 2

No, you should not generally provide the type if not needed.

Alternatives

While the solution to returns an object of a class with conversion operators could works, in may cases, them simplest solution would be to change the return value for an output parameter.

template <class T> void zero(T &t) { t = 0; }  // set_zero would be more readable

int x;
zero(x);

I would not consider that solution appropriate for that case as the following is much clearer:

auto x = zero<int>();

In practice, given that the default value is zero for numerical types and for most other types, then cannot be initialized from an integer or it might not have the intended result, it would be better to simply write:

int x = {};

or

int x {};

@AdamF 2020-08-01 12:20:34

Generally it is not possible to deduce function based on its return type. But if you use automatic types conversion c++ feature then you could achieve what you need:

template <typename T>
T zero() { return 1; }

template <>
float zero<float>() { return 3.0f; }

struct Zero
{
    template<typename T>
    operator T()
    {
        return zero<T>();
    }
};

int main()
{
    int x = Zero();
    float y = Zero();
    return x + y;
}

First you create temporary object Zero(), and during assigment we use conversion operator to execute correct specialization of zero template function.

@Asteroids With Wings 2020-08-01 12:23:58

Heh, cute workaround.

@Acorn 2020-08-01 12:53:15

Another elegant proof that conversion operators are evil ;-)

@Acorn 2020-08-01 12:17:10

So my question is, why g++ can deduce the type from argument list of template function

GCC follows the rules set forth by the C++ standard.

should I use foo(arg, ...) (provide the type) everytime, no matter the function declaration?

That depends on what you want to achieve. If you want to be explicit, do so. That would be similar to calling a foo_T() function in C which does not have templates nor overloads. However, if you want your code to be generic (for instance, because it is called in a template itself or because you want it easier to change on future type changes), then you would prefer to avoid writing the type explicitly.

Another option is using overloading rather than a template. Which one you use, again, depends on what you want and your use case.

Finally, you can also use auto instead:

auto zero() { return 0; }

Having said that, for signatures/interfaces, I think the best is to use explicit types everywhere unless there is a reason not to (e.g. it needs to be a template):

int zero() { return 0; }

@Asteroids With Wings 2020-08-01 12:13:30

It wouldn't have been impossible to define language rules to satisfy this case, but it would have been non-trivial and completely pointless.

This function has no business being a template, when all the information needed to decide its template argument is in the function. It should just return int, period. If you don't want to spell out the return type for whatever reason, this is what auto is for: it'll perform the deduction you seek.

On the other hand, if you want the 0 to be converted to different types for you depending on the template argument, then that makes more sense, and you already have the solution to that: provide the template argument (how could the computer guess it?). In this particular example you'd be better off just converting at the callsite, but presumably you have some more complex logic in mind.


As for whether you should always give template arguments explicitly, even when they are deducible, I'd say this is to some degree a matter of style. On the other hand it seems pretty pointless and noisy, but on the other it can be self-documenting and ensure that you're invoking the specialisation that you think you're invoking. So I think that this is going to depend on context.

Related Questions

Sponsored Content

17 Answered Questions

[SOLVED] Why can templates only be implemented in the header file?

6 Answered Questions

8 Answered Questions

2 Answered Questions

[SOLVED] C++ template deduction is not working

1 Answered Questions

2 Answered Questions

[SOLVED] Template deduction fails with argument after parameter pack

1 Answered Questions

[SOLVED] Nested template parameters and type deduction

3 Answered Questions

[SOLVED] Why is the template argument deduction not working here?

  • 2009-08-12 20:21:56
  • Juan
  • 4676 View
  • 27 Score
  • 3 Answer
  • Tags:   c++ templates

Sponsored Content