I am having this template matching error. I know partial specialization is not allowed in for function template, but I think it should work with full specialization. What change do I need to make to fix this issue ? Thanks.
#include <iostream>
template<typename T>
void allocate(){
std::cout << "default" << std::endl;
}
template<>
void allocate<int>() {
std::cout << "int" << std::endl;
}
template<>
void allocate<double>() {
std::cout << "double" << std::endl;
}
int main()
{
allocate(); // Compiler error, I expect this should match the first template function.
allocate<int>();
allocate<double>();
return 0;
}
You need to specify the template argument explicitly, the template parameter T can't be deduced from the context. e.g.
allocate<void>();
Or specify default argument for the template parameter, e.g.
template<typename T = void>
void allocate(){
std::cout << "default" << std::endl;
}
then you can call it as
allocate(); // T is void
The primary template needs the template parameter to be specified explicitly, so you can do:
allocate<struct T>(); // ok
and since T is a new type named only for the purpose of this call, there is guaranteed to not be a specialization for this type, and the primary template will be called.
You could also give a default type for the template parameter in the primary:
template<typename T = struct Default>
void allocate(){
std::cout << "default" << std::endl;
}
and again, no specialization can exist for Default since this type only exists in the scope of the primary template.
Now you can call the primary template without template parameters:
allocate();
Related
I'm trying to specialize a method of a (non-templated!) class. Apparently, it's not possible, however I am struggling to figure out why, or how to overcome the problem.
class MyClass {
public:
template <typename... T>
auto MyMethod(T... t) -> void { std::cout << "Original" << std::endl; }
template <typename... T>
auto MyMethod<int, T...>(int value, T... t) -> void { std::cout << "Specialization" << value << std::endl; }
};
int main(void) {
MyClass myClass;
myClass.MyMethod<char, char>('c', 'c');
myClass.MyMethod<int, char>(123, 'c');
return 0;
}
The error is as follows:
test.cpp:10:49: error: non-class, non-variable partial specialization ‘MyMethod<int, T ...>’ is not allowed
10 | auto MyMethod<int, T...>(int value, T... t) -> void { std::cout << "Specialization" << value << std::endl; }
It seems that there would be no reason for this to be impossible (with a template class it makes sense that the entire class has to be specialized too). What am I missing? Is it literally not possible?
Only classes can be partially specialized; methods can only be fully specialized. As your methods still have template arguments (T) that are not specified, this means a partial method specialization.
If you would use these template arguments for a class (and call a non-templated member function of that class) then this should be possible.
I have a situation where I need overload resolution to prefer an overload with an implicit conversion over a template function with the same name.
Consider the following example:
#include <iostream>
#include <functional>
void call_function(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
template <typename Function>
void call_function(const Function& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function();
}
int main()
{
// Pass a lambda to "call_function"
// This lambda is implicitly convertible to 'std::function<void()>'
// Even though it is implicitly convertible, the template function is selected by the compiler.
call_function([]{
std::cout << "TEST" << std::endl;
});
}
Output:
CALL FUNCTION 2
TEST
Unfortunately, the compiler seems to detect that the first implementation of call_function would require an implicit conversion to convert the lambda I pass it into a std::function<void()> object and because of this it determines that the template version is a better match and uses the template. I need to force the compiler to prefer the implicit conversion overload over the template so the output would be:
CALL FUNCTION 1
TEST
How can I achieve this? (Also note that I am restricted to a C++11 compliant compiler so I am unable to use features from C++14 and beyond)
Overload resolution will never prefer an implicit conversion over an exact match. Since the template will always match exactly, the only way to get the non-template selected is to assure that it doesn't require any conversion either.
To do that, you can cast the closure (the result of the lambda expression) to the correct type first:
call_function(static_cast<std::function<void()>>([]{
std::cout << "TEST" << std::endl;
}));
Now what's passed is exactly the type taken by the first overload ("FUNCTION 1") so that's what'll be selected.
That said, if you care about which one is called, you probably shouldn't be using overloading. Overloading should normally be reserved for situations where the overloads are essentially equivalent, so you really don't care which gets called.
If you want to change the overloads such that the former overload is chosen whenever there is an implicit conversion possible, with the latter being the backup, you can do this with SFINAE via std::enable_if:
#include <type_traits>
void call_function(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
template <typename Function,
// Consider this overload only if...
typename std::enable_if<
// the type cannot be converted to a std::function<void()>
!std::is_convertible<const Function&, std::function<void()>>::value,
int>::type = 0>
void call_function(const Function& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function();
}
Demo
Alternatively, if you want to be able to support an unknown number of overloads of call_function with the "CALL FUNCTION 2" being a backup overload in case none of the functions work, you can do this too, but it requires quite a bit more work:
// Rename the functions to `call_function_impl`
void call_function_impl(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
void call_function_impl(const std::function<void(int, int)>& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function(1, 2);
}
// The backup function must have a distinct name
template <typename Function>
void call_function_backup_impl(const Function& function)
{
std::cout << "CALL FUNCTION backup" << std::endl;
function();
}
// Implement std::void_t from C++17
template <typename>
struct void_impl {
using type = void;
};
template <typename T>
using void_t = typename void_impl<T>::type;
// Make a type trait to detect if the call_function_impl(...) call works
template <typename Function, typename = void>
struct has_call_function_impl
: std::false_type
{};
template <typename Function>
struct has_call_function_impl<Function,
void_t<decltype(call_function_impl(std::declval<const Function&>()))>>
: std::true_type
{};
// If the call_function_impl(...) call works, use it
template <typename Function,
typename std::enable_if<
has_call_function_impl<Function>::value,
int>::type = 0>
void call_function(const Function& function)
{
call_function_impl(function);
}
// Otherwise, fall back to the backup implementation
template <typename Function,
typename std::enable_if<
!has_call_function_impl<Function>::value,
int>::type = 0>
void call_function(const Function& function)
{
call_function_backup_impl(function);
}
Demo
I wrote a trivial example, which is somehow compiles.
#include <iostream>
using namespace std;
template <int A>
void func()
{
cout << 1 + A << endl;
return;
}
int main()
{
// I can not even use this strange func()
int a = 1; func(a); // this does not compile
func(1); // this does not compile as well
return 0;
}
This example frustrates me a lot:
First, I gave non-type template parameter to template, but did not provide any parameters (in parentheses) to function itself. Looks like template parameter becomes the function parameter, but why?
Second, even though it compiles, I can not find a way to use this template, see my comments in main.
And third, what is the reason for existence of template functions with non-type template parameter of integral type? How is it any different from having a regular function?
int A is not a function parameter, it's a template parameter. func takes no arguments and you instantiate/call it like this:
func<1>(); // compile-time constant needed
Please review C++ function templates. You can't use template parameters in the way you want.
On the other hand, having a type template parameter and one function parameter:
template <typename A>
void func(A a)
{
cout << 1 + a << endl;
}
will make your program valid. Maybe that's what you wanted.
Edit:
To your request, here's a usage of such non-type function template parameter:
template <size_t S>
void func(const int (&array)[S])
{
cout << "size of the array is: " << S << endl;
}
or std::array version:
template <size_t S>
void func(std::array<int, S> const& array)
{
cout << "size of the array is: " << S << endl;
}
S here is deduced to the size of the passed array.
I have come across this piece of code (I'm trying to include all details in case I'm missing something):
template< typename TYPE = TYPE_with_an_arbitrarily_long_name,
typename KIND = KIND_with_an_arbitrarily_long_name>
class Foo
{
public:
virtual void bar(TYPE& t, KIND& k) = 0;
};
And the part I don't understand is the assignments inside the template:
template <typename TYPE = TYPE_with_an_arbitrarily_long_name, ..
I have been trying to understand the effect of this but so far I couldn't produce any. Here are some stuff I have tried:
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T>
void foo(T t) {
cout << typeid(t).name() << " ";
}
template<typename T = int>
void bar(T t) {
cout << typeid(t).name() << " ";
}
template<typename T = double>
void baz(T t) {
cout << typeid(t).name() << " ";
}
int main()
{
cout << "\nfoo: ";
foo(3); foo<int>(3); foo<double>(3);
cout << "\nbar: ";
bar(3); bar<int>(3); bar<double>(3);
cout << "\nbaz: ";
baz(3); baz<int>(3); baz<double>(3);
return 0;
}
prints out:
foo: i i d
bar: i i d
baz: i i d
So my question is:
What is the effect of assignment inside template?
What is the purpose of using it in the above example?
There is no third question.
Any help is appreciated..
EDIT turned out functions are only compilable with c++11
This is called 'default template argument' and specifies which type is used, when none is specified - alike default function parameters. This technique is widely used for classes - look at definition of std::vector or std::string, and you will see they have multiple default type parameters.
Best use for default type parameters for function templates is when type argument cannot be easily deduced from actual arguments, and it is not specified explicitly - then compiler will use default one. In your example there is no need for default types, because it can be easily deduced from actual call parameters.
Until C++0x default type parameters were allowed only for class templates - they were not possible to use with function templates. With C++0x it changed, but some older compilers (for example Visual C++ 2008) would not let you to use them.
These are not assignments but rather “default values” for the type arguments of the template, much like there is a similar syntax for default value arguments of functions. They are used when an explicit argument is not specified.
For bar and baz function templates in your example, it makes no sense because for these functions, T will be derived from the specified arguments.
A function-template may not be the best construct to demonstrate default template arguments. Here's something similar with template-structs:
#include <iostream>
#include <typeinfo>
template<typename T = int>
struct foo {
static void f() {
std::cout << typeid(T).name() << "\t";
}
};
template<typename T = double>
struct bar {
static void f() {
std::cout << typeid(T).name() << "\t";
}
};
int main() {
foo<>::f(); foo<int>::f(); foo<double>::f(); std::cout << std::endl;
bar<>::f(); bar<int>::f(); bar<double>::f(); std::cout << std::endl;
}
Running this, I get:
% ./a.out
i i d
d i d
The "assignments" inside the template parameter list are default parameters, just as in function parameter lists. That means in your example, Foo<> is the same as Foo<TYPE_with_an_arbitrarily_long_name, KIND_with_an_arbitrarily_long_name>, and Foo<int> is the same as Foo<int, KIND_with_an_arbitrarily_long_name>.
It will not be used in your examples. You don't use Foo at all, and the parameters of baz and bar will always be deduced by the compiler from the given arguments.
These are default template arguments. You can use template default arguments to simplify their usage.
When you have two template parameters, for example, and give the last one a default type, you must specify only one type.
std::vector, for example, is defined as
template < class T, class Allocator = allocator<T> > class vector;
Here you have a default template argument for Allocator, so you can define vectors with just one argument
std::vector<int> v;
What you are looking for is "Template Specialization"
Here's a link to some Example/Explanation
I am learning function templates just now and I wanted to research a bit rules of function templates instantiation. So I've written the following code:
#include <iostream>
template <typename>
int check(int x) {
return x * 2;
}
int main() {
std::cout << check<double>(10) << std::endl; // #1
std::cout << check<>(10) << std::endl; // #2
std::cout << check(10) << std::endl; // #3
return 0;
}
The lines #1, #2 and #3 are not compiled all together, each try I leave only one of them and comment the rest.
So, when #1 is enabled, I have no compilation errors and the correct answer "20" is printed. As I understand, "check<"double">" invokes template instantiation mechanism so "int check(int)" function is really created (the type of template parameter doesn't have any influence).
When #3 is enabled, I have a compilation error "error: no matching function for call to 'check(int)'", which is reasonable, since I am trying to call to "check(int)" function which doesn't exist. My question is regarding #2 case: in this case I get the same "error: no matching function for call to 'check(int)'". Shouldn't call "check<>(10)" trigger template instantiation mechanism as well?
You don't put any template parameter in the <>. How can compiler know which template function to instantiate? Please notice that your template function is:
template <typename>
int check(int x)
If you change it to this:
template <typename T>
int check(T x)
then check<>(10) should be fine because the complier can know the type from the parameter.
I have to say that usually template doesn't go that way:(
Try this one:
template<typename T>
T check(T x){
return x*2;
}
The only template instantiation you'll get is with
check<double>(10)
The others don't instantiate the template. Also for the full power of function templates include the template argument as
template<typename T>
T check(T x) {
return x*2;
}
Then using the power of template argument deduction you can call
check(10.0); // instantiates check<dobule>
check(3); // instantiates check<int>
or
a = MyObject();
check(a); // instantiates check<MyObject>
#2 would be valid if the template argument could be deduced.
#include <iostream>
template <class T>
void foo(T t)
{
std::cout << "Template " << t << '\n';
}
void foo(int n)
{
std::cout << "Not template " << n << '\n';
}
int main()
{
foo(10); //calls non-template function
//because matching non-template preferred over function templates
foo<>(10); //calls the template function, empty brackets indicate you want
//the template overload, type is deduced from passed argument.
}
Another possibility, if the function template had default arguments (only legal in C++11).
template <class T = void>
int foo()
{
return 10;
}
int main()
{
return foo<>(); //same as foo<void>();
}
If you don't pass a template argument, it is equivalent to looking for the function without a template argument (i.e. it doesn't instantiate the template). The added <> means nothing in this case because there are is no overloading.
Since the function you have doesn't actually use the template for anything and the compiler thus can't infer the type T, but if you write it like this:
template <typename T>
T check(T x) {
return x * 2;
}
Then all 3 cases will work, since it infers the type T. See https://stackoverflow.com/a/797632/888641 for more explanation.
Note: You can use typename or class, they do the exact same thing here.