Difference Between Function Template and Template Function

What is the difference between function template and template function?

The term "function template" refers to a kind of template. The term "template function" is sometimes used to mean the same thing, and sometimes to mean a function instantiated from a function template. This ambiguity is best avoided by using "function template" for the former and something like "function template instance" or "instance of a function template" for the latter. Note that a function template is not a function. The same distinction applies to "class template" versus "template class".

From this FAQ (archive)

What are the key differences between a generic lambda, a template function and a template member operator() during argument deduction?

A template is a language construct of C++ which generates other constructs: classes, functions, or variables (in C++14). The name of a template, without its template parameters, can only be used in very limited ways.

comp1 names a template, not a function. That's the important point. A function template is a construct that generates a function when you provide specific template parameters; comp1<int> is the name of a function. But the name by itself names the template, not a function it generates.

The name of a function template can be called (ie: comp1(arg1, arg2)) because of a special rule of C++ called "template argument deduction". In short, the compiler deduces the types of the template arguments to comp based on the declaration of comp and the nature of the arguments provided to the function call. But this only works because C++ has a rule that says that it does.

The name of a template alone (like comp1) is not an expression, and a function call expects expressions (or braced-init-lists) to be given as arguments. The error "cannot deduce argument error" is not about deduction within std::sort; it's about deducing the template arguments for std::sort itself. comp1, a template, has no type, so it cannot participate in argument deduction.

comp2 names a variable, as does comp3. Both of these are expressions, so both can be passed to functions.

Yes, the types of both comp2 and comp3 contain a function template. But comp2 and comp3 as names name variables, not the function templates they contain. So they work like any other variable.

As for a generic lambda, that is no different from any other user-defined type with a template operator() method.

Equivalence between function templates and abbreviated function templates

This:

template <typename T>
void e(T, auto);

Translates to this:

template<typename T, typename U>
void e(T, U);

By contrast, this:

template <typename T>
void e(auto, T) {}

translates to:

template <typename T, typename U>
void e(U, T) {}

Remember that abbreviated function template parameters are placed at the end of the template parameter list. So those aren't declaring the same template, due to reversing the order of the template parameters. The first one declares one template, the second one declares and defines a different template.

You don't get a compile error just from this because the second definition is also a declaration. However, when you use a class member, out-of-member definitions are not declarations. Therefore, they must have a matching in-member declaration. Which they don't; hence the errors.


As for the others, the "functionally equivalent (but not equivalent)" text is a non-normative notation. The actual normative text that you quoted clearly states that these are "equivalent", not merely "functionally equivalent". And since the term "equivalent", per [temp.over.link]/7, is used to match declarations and definitions, it seems to me that the standard states that the A through D cases are fine.

What's weird is that this non-normative text was introduced by the same proposal that introduced the normative text. However, the proposal that it inherited the ConceptName auto syntax from seems clear that it means "equivalent", not "functionally equivalent".

So in terms of normative text, everything seems clear. But the presence of the non-normative contradiction suggests either an editorial problem or an actual defect in the spec.


While the standard itself is clear and normatively reasonable in terms of wording, it appears that this is not what the writers of the standard intended.

P0717 introduced the concept of "functionally equivalent" as being distinct from "equivalent". And that proposal was accepted. However, P0717 was introduced early in the process of adopting the Concepts TS for C++20. In that proposal, it specifically spoke of terse template syntax, and EWG explicitly voted in favor of adopting "functionally equivalent" wording for it instead of the Concepts TS "equivalent" wording.

That is, P0717 makes it clear that the committee intended for users to be required to use consistent syntax.

However, terse template syntax from Concepts TS was removed from C++20 (or rather, never really added). Which meant that any "functionally equivalent" wording never made it in, since the feature never made it in.

Then P1141 happened, which added abbreviated template syntax, that covered much of the ground of the Concepts TS terse template syntax. But, despite one of the authors of P0717 being an author of P1141, apparently someone made a mistake in the wording and nobody caught it. This would explain why the non-normative text calls out the lack of true equivalence: because that was actually the committee's intent.

So it's very possible that this is a mistake in the normative text.

What is the difference between a template class and a class template?

This is a common point of confusion for many (including the Generic Programming page on Wikipedia, some C++ tutorials, and other answers on this page). As far as C++ is concerned, there is no such thing as a "template class," there is only a "class template." The way to read that phrase is "a template for a class," as opposed to a "function template," which is "a template for a function." Again: classes do not define templates, templates define classes (and functions). For example, this is a template, specifically a class template, but it is not a class:

template<typename T> class MyClassTemplate
{
...
};

The declaration MyClassTemplate<int> is a class, or pedantically, a class based on a template. There are no special properties of a class based on a template vs. a class not based on a template. The special properties are of the template itself.

The phrase "template class" means nothing, because the word "template" has no meaning as an adjective when applied to the noun "class" as far as C++ is concerned. It implies the existence of a class that is (or defines) a template, which is not a concept that exists in C++.

I understand the common confusion, as it is probably based on the fact that the words appear in the order "template class" in the actual language, which is a whole other story.

Differences between template specialization and overloading for functions?

I can only think of a few differences - here are some examples that don't necessarily cause harm (i think). I'm omitting definitions to keep it terse

template <typename T> T inc(const T& t);
namespace G { using ::inc; }
template <> int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses explicit specialization

// --- against ---

template <typename T> T inc(const T& t);
namespace G { using ::inc; }
int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses template

That is because specializations are not found by name lookup, but by argument matching, so a using declaration will automatically consider a later introduced specialization.

Then, you of course cannot partially specialize function templates. Overloading however accomplishes something very similar by partial ordering (using different types now, to make my point)

template <typename T> void f(T t); // called for non-pointers
template <typename T> void f(T *t); // called for pointers.

int a;
void e() {
f(a); // calls the non-pointer version
f(&a); // calls the pointer version
}

That wouldn't be possible with function template explicit specialization. Another example is when references are involved, which causes template argument deduction to look for an exact match of the types involved (modulo base/derived class relationships and constness):

template<typename T> void f(T const &);
template<> void f(int * const &);

template<typename T> void g(T const &);
void g(int * const &);

int a[5];
void e() {
// calls the primary template, not the explicit specialization
// because `T` is `int[5]`, not `int *`
f(a);

// calls the function, not the template, because the function is an
// exact match too (pointer conversion isn't costly enough), and it's
// preferred.
g(a);
}

I recommend you to always use overloading, because it's richer (allows something like partial specialization would allow), and in addition you can place function in whatever namespace you want (although then it's not strictly overloading anymore). For example, instead of having to specialize std::swap in the std:: namespace, you can place your swap overload in your own namespace and make it callable by ADL.

Whatever you do, never mix specialization and overloading, it will be a hell of a mess like this article points out. The Standard has a lovely paragraph about it

The placement of explicit specialization declarations for function templates, class templates, member functions of class templates, static data members of class templates, member classes of class templates, member class templates of class templates, member function templates of class templates, member functions of member templates of class templates, member functions of member templates of non-template classes, member function templates of member classes of class templates, etc., and the placement of partial specialization declarations of class templates, member class templates of non-template classes, member class templates of class templates, etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.

What is the difference between a Function Template and a Delegate?

A delegate is a way of taking a member function of some object, and creating a...thing that can be called independently.

In other words, if you have some object A, with some member function F, that you'd normally call as something like: A.F(1);, a delegate is a single entity that you can (for example) pass as a parameter, that acts as a proxy for that object/member function, so when the delegate is invoked, it's equivalent to invoking that member function of that object.

It's a way of taking existing code, and...packaging it to make it easier to use in a fairly specific way (though I feel obliged to add, that 'way' is quite versatile so delegates can be extremely useful).

A C++ function template is a way of generating functions. It specifies some set of actions to take, but does not specify the specific type of object on which those actions will happen. The specification is at a syntactic level, so (for example) I can specify adding two things together to get a third item that's their sum. If I apply that to numbers, it sums like you'd expect. If I do the same with strings, it'll typically concatenate the strings. This is because (syntactically) the template just specifies something like a+b, but + is defined to do addition of numbers, and concatenation of strings.

Looked at slightly differently, a function template just specifies the skeleton for some code. The rest of that code's body is "filled in" based on the type, when you instantiate the template over some specific type.

Template function with multiple parameters of same type

If you change the function into a functor, you can introduce a parameter pack in the body of the type of the functor.

First create a helper to turn <N, T> -> std::tuple<T, T, T, ..., T> (N times):

template<std::size_t N, typename T>
struct repeat {
private:
// enable_if<true, T> == type_identity<T>
template<std::size_t... I>
static std::enable_if<true, std::tuple<std::enable_if_t<I==I, T>...>>
get(std::index_sequence<I...>);
public:
using type = typename decltype(get(std::make_index_sequence<N>{}))::type;
};

Then have your functor take a std::tuple<Args...>, where Args will be a parameter pack with T N times:

template<typename T, typename Args>
struct fun_t;

template<typename T, typename... Args>
struct fun_t<T, std::tuple<Args...>> {
static constexpr std::size_t argsCount = sizeof...(Args);

void operator()(Args... args) const {
// ...
// std::array<T, argsCount>{ args... };
}
};

template<std::uint32_t argCount, typename T>
constexpr fun_t<T, typename repeat<argCount, T>::type> fun;


int main() {
fun<3, Foo>({ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 });
}


Related Topics



Leave a reply



Submit