Need help regarding Template class instantiation - c++

Let me present my problem with an example :
template <typename T> class a{
public:
T data;
a():data(T()){}
a(T temp): data(temp) {}
};
So if write in main() like
a(30);
a("String");
So according to the template argument deduction rule , it should be able to generate the first temporary class as a<int>(30) etc
But I the error which says:
missing template arguments before '(' token
so why this happens, this is only true for function template?

Template parameter deduction from arguments only works for functions, never for classes. Until you know the type of the class, i.e. all its template parameters, you don't even know which member functions the class has!
So, you always have to say the template parameters if you want to construct an object directly:
a<int> x(30);
Here's a little thought experiment to expand on the above. Suppose we have
template <typename T> class Foo;
and we are calling Foo::somefunction(x);, where x is some type. You think, well, I declared somefunction() like this:
template <typename T> class Foo
{
static void somefunction(const T & x);
};
so it should be obvious that T is the same type as the type of x. But now imagine I have a specialization:
template <> class Foo<char>
{
static void anotherfunction(double x);
};
The class Foo<char> doesn't even have a function somefunction(), so the expression Foo::somefunction(x) doesn't even get to the stage where I could look up the argument!
The usual way around this is to make a free helper function that constructs your object:
template <typename T> a<T> make_a(const T & x) { return a<T>(x); }
Since this is a function template, its parameters can be deduced:
make_a(30); // type a<int>
make_a("hello"); // type a<char[6]>

The constructor is not a template, its the class which is a template. So when you write a(30), the template argument deduction for the class template cannot be done!
If there exists a constructor template, then the template argument for the templated constructor can be deduced by the compiler. For example here:
template <typename T> class A{
public:
template<typename U>
A(const U &): {} //note : it's a constructor template
};
A<char> obj(30); //U is deduced as int
In the above example, only U can be deduced, you still have to provide T. Its because
U is a template argument for the constructor template. Template argument deduction can be done in this case.
T is a template argument for the class template. Template argument deduction cannot be done here.

You still need to declare a temporary as, for example, a<int>(30).

You cannot infer class template arguments from the arguments to the constructor- unfortunately.

Template type deduction only happens for template functions. You need to specify the parameters for a template class instantiation . You can use a function template to deduce the template parameter and return the appropriate type. In c++0 x you could use auto to hold the instance. Can't easily write example code for you on my phone!

Related

Defaulted Template in Template Function Requires Empty Angle Brackets <>

gcc 11.2 can't seem to compile this:
template <typename T = int>
struct Test {};
template <typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test>(t);
}
but has no problem with
template <typename T = int>
struct Test {};
template <typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test<>>(t);
}
Is this a compiler bug?
This question seems to suggest it should work.
GCC is right. An empty template argument list, <> for a function template is allowed to be omitted ([temp.arg.explicit]/4). In other cases, the template argument list is generally required in order to name a particular specialization of a template, even if it is empty. See the grammar for simple-template-id, [temp.names]/1.
As a limited exception to the rule, if the name of a class template without a template argument list appears in a context where a concrete type is required, it is known as a "placeholder for a deduced class type" and this is only allowed in specific contexts listed in [dcl.type.class.deduct]. The most common one is a variable declaration like std::pair p("foo", 1) where the compiler will deduce std::pair<const char*, int> in C++17 and later.
In your code, you are trying to refer to a particular specialization of class template Test, without specifying the template argument list, and not in a context where the template arguments can be deduced. Therefore, it's not allowed.
The new Class template argument deduction (CTAD) (since C++17) is applied to declarations. The expression foo<Test<>>(t); is not a declaration, it is a template function call.
In your first code snippet, you specify a class template (Test) as a template parameter to foo and not a type (like an instance of a class template). You would need a function that takes a template template parameter to handle that.
Example:
#include <type_traits>
template<template<class> class T, class U> // T = Test, U = deduced to int
void foo(T<U>& bar) {
std::cout << std::is_same<T<U>, Test<int>>::value << '\n'; // true
}
int main() {
Test t;
foo<Test>(t); // now ok
}
In your second snippet, foo<Test<>>(t); instantiates foo<Test<int>>(Test<int>&); since <> makes the template instantiation use the default type for the template parameter, which is int.

Template argument deduction from inherited type

I want a setup like the following:
template <typename T> class a {};
class b : public a<int> {};
template <typename T>
void do_foo(std::unique_ptr<a<T>> foo)
{
// Do something with foo
}
int main()
{
do_foo(std::make_unique<b>());
}
This fails to compile with a note saying template argument deduction/substitution failed and mismatched types 'a<T>' and 'b'. It's pretty self-explanatory. I can help the compiler along by writing do_foo<int>(std::make_unique<b>());, but then I'm repeating myself by writing int twice.
Is there a way to get the compiler to deduce the template parameter in this case? And what would you call this behaviour? I tried searching for things like "template type deduction for inherited type", "polymorphic template deduction" etc.
Is there a way to get the compiler to deduce the template parameter in this case?
No. Not in C++14 (or even C++20).
And what would you call this behaviour?
Standard compliant. To be specific, this paragraph applies:
[temp.deduct.call]
4 In general, the deduction process attempts to find template
argument values that will make the deduced A identical to A (after
the type A is transformed as described above). However, there are
three cases that allow a difference:
If the original P is a reference type, the deduced A (i.e., the type referred to by the reference) can be more cv-qualified than the
transformed A.
The transformed A can be another pointer or pointer to member type that can be converted to the deduced A via a qualification
conversion ([conv.qual]).
If P is a class and P has the form simple-template-id, then the transformed A can be a derived class of the deduced A.
Likewise, if P is a pointer to a class of the form
simple-template-id, the transformed A can be a pointer to a derived class pointed to by the deduced A.
This is an exhaustive list of cases where a template argument can be validly deduced from a function argument even if it doesn't match the pattern of the function parameter exactly. The first and second bullets deal with things like
template<class A1> void func(A1&){}
template<class A2> void func(A2*){}
int main() {
const int i = 1;
func(i); // A1 = const int
func(&i); // A2 = const int
}
The third bullet is the one that is closest to our case. A class derived from a template specialization can be used to deduce a template parameter pertaining to its base. Why doesn't it work in your case? Because the function template parameter is unique_ptr<a<T>> and the argument you call it with is unique_ptr<b>. The unique_ptr specializations are not themselves related by inheritance. So they don't match the bullet, and deduction fails.
But it doesn't mean that a wrapper like unique_ptr prevents template argument deduction entirely. For instance:
template <typename> struct A {};
struct B : A<int> {};
template<typename> struct wrapper{};
template<> struct wrapper<B> : wrapper<A<int>> {};
template<typename T>
void do_smth(wrapper<A<T>>) {}
int main() {
do_smth(wrapper<B>{});
}
In this case, wrapper<B> derives from wrapper<A<int>>. So the third bullet is applicable. And by the complex (and recursive) process of template argument deduction, it allows B to match A<T> and deduce T = int.
TL;DR: unique_ptr<T> specializations cannot replicate the behavior of raw pointers. They don't inherit from the specializations of unique_ptr over T's bases. Maybe if reflection ever comes to C++, we'll be able to meta-program a smart pointer that does behave that way.
As workaround, you might add overload:
template <typename T>
void do_foo_impl(a<T>* foo)
{
return do_foo(std::unique_ptr<a<T>>(foo));
}
template <typename T>
auto do_foo(std::unique_ptr<T> foo) -> decltype(do_foo_impl(foo.release()))
{
do_foo_impl(foo.release());
}
Demo

Function pointer definition inside a class template based on the template variable arguments

using FuncDef = void(int a, int b);
template <typename R, typename... Args>
class WrongFunction {
public:
void F1(R(*Fn)(Args...)) {}//error: C2091 function returns function
};
template <typename T> class Function;
template <typename R, typename... Args>
class Function<R(Args...)> {
public:
void F1(R(*Fn)(Args...)) {}
};
void test() {
WrongFunction<FuncDef> errfunc;//trigger the above compilation error
Function<FuncDef> func;//no problem
}
(1) Why Function works but WrongFunction doesn't (check the compilation error in the comment)? What is the theory behind (e.g. something from cppreference which contains every details about C++)?
(2) (optional) Is there a way to make WrongFunction work but not in the form as Function?
The follow class template:
template <typename R, typename... Args>
class WrongFunction {
public:
void F1(R(*Fn)(Args...)) {}//error: C2091 function returns function
};
defines a template parameter API which expects:
a return type R, and
a variadic number of arguments (of possible different types) Args.
Now, a template parameter pack may be empty, which hides your actual error here. In the instantiation of of the WrongTemplate class template:
WrongFunction<FuncDef> errfunc;
you provide only a single template argument, which matches the first template parameter of the class template:
FuncDef is used as argument for R in WrongFunction
whereas you are providing no argument for template parameter pack.
Thus, the compilers' error message is quite telling: you are instantiating the WrongFunction class template with a template argument provided for the template parameter R, which semantically signifies a return type, but with a function type argument. Meaning, in the associated specialization, R is a function type;
void F1(R(*Fn)(Args...)) {}
// resolves to, for WrongFunction<FuncDef> specialization
void F1( (void)(*)(int, int) (*Fn)() ) {}
// ^^^^^^^^^^^^^^^^^^^ <- R
thus defining a function parameter that is declared to have the type "pointer to function (named Fn) with zero arguments that return a pointer to function with two arguments that return void". This is illegal, thus the compiler error.
In your other class template, you leverage specialization, constructing the primary class template API to have a single type template parameter, semantically intended to be provided arguments that are of type "pointer to function", as the the only partial specialization (as the primary template is not defined) is specifically partially specialized for this kind of argument.
(2) (optional) Is there a way to make WrongFunction work but not in the form as Function?
The template parameter API of WrongFunction expects the client to explicitly provide the return type for the intended function pointer (of the member function) and the argument types by separate template arguments. It basically does not rely on deduction. Your second approach with specialization is the common one, and instead of fixing the likely ill-designed WrongFunction, I will note a similar but slightly different design of Function, which embeds a function pointer into its type instead. Thus could be useful if the member function of a given specialization should only use delegation to a specific function, rather than allowing dynamic dispatch delegation via function pointers of specific function pointer type (as function parameter to the member function).
#include <utility>
template <auto> class Function;
template <typename R, typename... Args, R (*Fn)(Args...)>
class Function<Fn> {
public:
template <typename... FnArgs /* optionally SFINAE that FnArgs is Args */>
void F1(FnArgs &&... args) {
Fn(std::forward<FnArgs>(args)...);
}
};
void f(int a, int b) {}
int main() {
Function<f> func;
func.F1(1, 2);
}

Template arguments can't be omitted when specializing this function template

In C++, Explicit specializations of function templates is like:
template<typename T> return_type fun_name();
template<> return_type fun_name<int>(){/* blabla */}
The <int> in the above example is called template argument. Sometimes <int> can be ommitted because compiler can do Template Argument Deduction
But I can't find out why Template Argument Deduction failed in the following example:
//-------------failed case-------------
template <typename T>
struct deduce{
typedef T* type;
};
template <typename T>
typename deduce<T>::type fun1();
template <>
typename deduce<float>::type fun1<float>() //error if no "<float>" after fun1
{
}
//------------now the "Template Argument Deduction" works------------
template <typename T>
struct some_struct{
T* p;
};
template <typename T>
some_struct<T> fun2();
template <>
some_struct<float> fun2() // no error even if no "<float>" after fun2
{
}
If no <float> is after fun1, The error message is:
error: template-id ‘fun1<>’ for ‘float* fun1()’ does not match any template declaration
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
Let me provide an example of why non-deduced contexts are non-deduced. Template deduction is basically trying to match on the input. If I had:
template <class T> void foo(T );
and I call foo(4), that's easy. T=int. If I call foo('x'), T=char. These are easy substitutions to make. If T is nested somewhere in the type, like:
template <class T> void bar(std::vector<T> );
that's still totally doable. If I call it with a std::vector<std::vector<float>>, T=std::vector<float>. Still no problem.
Now consider this one:
template <class T> void baz(typename X<T>::type );
baz(4);
What's T? In all our previous cases, there was one obvious choice for T that was deduced directly from the argument passed to the function template. But here, that's not the case. We have an extra layer of indirection - we need to deduce a T to make a type X<T> whose member typedef type is int. How do we find such a thing?
Now let's say we had this:
template <class T> struct X { using type = T; };
Ok now it's easy right? T=int? Well, not so fast. For the primary template, that would work in this case. But what if there was also this specialization:
template <class T> struct X<T*> { using type = T; };
(that is, X is std::remove_pointer). Now we're in a situation where T=int works... but T=int* also works. And maybe there's some other type out there that also works for int. How do you pick the right one?
This problem - picking a template parameter in the nested-name specifier of qualified-id - is really hard and has no obvious path forward. So the compiler just won't take a path forward. It's a non-deduced context. T will never be deduced in the call to baz, the caller has to provide it:
baz<int>(4); // ahhhhh, ok, you wanted X<int>::type
Back to your question. some_struct<T> is a deduced-context, but typename deduce<T>::type is a non-deduced context. I hope it's clear now why the former works but the latter doesn't.
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
It has nothing to do with typename, the point is that deduce<T>::... is a nested-name-specifier; which belongs to Non-deduced contexts:
(emphasis mine)
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
So, for
template <>
typename deduce<float>::type fun1()
deduce<float>::type (i.e. float*) will be used to deduce type T for deduce<T>::type, but T won't be deduced, template argument deduction fails. You have to explicitly specify it as float.

what does template<> (without any class T in the <>) mean?

I'm reading some source code in stl_construct.h,
In most cases it has sth in the <>
and i see some lines with only "template<> ...".
what's this?
This would mean that what follows is a template specialization.
Guess, I completely misread the Q and answered something that was not being asked.
So here I answer the Q being asked:
It is an Explicit Specialization with an empty template argument list.
When you instantiate a template with a given set of template arguments the compiler generates a new definition based on those template arguments. But there is a facility to override this behavior of definition generation. Instead of compiler generating the definition We can specify the definition the compiler should use for a given set of template arguments. This is called explicit specialization.
The template<> prefix indicates that the following template declaration takes no template parameters.
Explicit specialization can be applied to:
Function or class template
Member function of a class template
Static data member of a class template
Member class of a class template
Member function template of a class template &
Member class template of a class template
It's a template specialization where all template parameters are fully specified, and there happens to be no parameters left in the <>.
For example:
template<class A, class B> // base template
struct Something
{
// do something here
};
template<class A> // specialize for B = int
struct Something<A, int>
{
// do something different here
};
template<> // specialize both parameters
struct Something<double, int>
{
// do something here too
};