I want to have a templated friend function. However, I do not know how to make it works in the same way for no templated function.
Here is a sample code
#include <iostream>
namespace ns{
struct Obj {
friend void foo(Obj){std::cout << "no problem" << std::endl;}
template<typename T>
friend void bar(Obj){std::cout << "problem" << std::endl;}
};
}
int main() {
ns::Obj obj;
foo(obj); // Compile
bar<int>(obj); // Not compile
return 0;
}
Before C++20, you need to teach the compiler that bar is the name of a template so that it knows that < starts a template argument list and is not the less-than operator:
template<char> void bar() = delete;
int main() {
ns::Obj obj;
foo(obj); // Compile
bar<int>(obj); // Now compiles too
return 0;
}
Note that all the bar overload has to do is to be a function template. The signature doesn't matter as long as it's not so good as to interfere with the overload resolution; () is a good choice because by definition we are passing at least one argument, so a function template taking no parameters can never be viable.
Alternatively, you can redesign bar to deduce T from a tag argument:
template<class T>
struct type {};
namespace ns{
struct Obj {
// ...
template<typename T>
friend void bar(Obj, type<T>) { /* ... */ }
};
}
// ...
bar(obj, type<int>()); // OK
In C++20, the compiler will assume that bar names a template when it sees the < and name lookup finds nothing, so your code will just work.
The straightforward approach would be to add a forward declaration and let the function be located using qualified lookup:
namespace ns{
struct Obj;
void foo(Obj);
template<typename T>
void bar(Obj);
struct Obj {
friend void foo(Obj){std::cout << "no problem" << std::endl;}
template<typename T>
friend void bar(Obj){std::cout << "problem " << std::endl;}
};
} // namespace ns
int main() {
ns::Obj obj;
ns::foo(obj); // Ok
ns::bar<int>(obj); // Ok
return 0;
}
Related
Here is a problem I stumbled accross when refactoring some code and I was wondering if there is a better way to do it:
#include <iostream>
template<typename T>
class Foo
{
public:
Foo()
{
init(x);
}
T x;
};
void init(int& i)
{
i = 42;
}
int main()
{
Foo<int> foo;
std::cout << foo.x << std::endl;
return 0;
}
Unfortunately, this doesn't compile - neither with GCC or with Clang. The function init called in Foo's constructor is not declared. In this toy example, this could be solved by moving the function itself ahead of the template. However, in a more complex context, this may not work. Originally, I intended to use overloads of init to allow some setup for the classes used in the template.
I assumee that in this context init is a non-dependend name - even though the argument of the function call depends on the template parameter (which was odd for me at first). Is there a way to trick it to also consider function definitions defined after the template itself?
I know that I can use template specialization (which was in the original code in the first place, but I wanted to replace it with simpler overloads):
template<typename>
struct Initializer;
template<>
struct Initializer<int>
{
static void init(int& i)
{
i = 42;
}
}
Is there a way to make this work with function overloads as well? I know, boost::serialization also relies on function overloads for custom types, but I did not really find where and how they implemented that.
You can solve the ordering problem by calling through a template function object - in the same way that boost::hash finds the ADL-function hash_value(x).
This works because the expansion of the template is deferred until the point of first use:
#include <iostream>
namespace A {
struct XX {
friend void init(XX&);
};
}
namespace B {
struct YY {
friend void init(YY&);
};
}
/// default case - call init on T found by ADL
template<class T>
struct call_init
{
void operator()(T& o) const {
init(o);
}
};
template<typename T>
class Foo
{
public:
Foo()
{
auto initialiser = call_init<decltype(this->x)>();
initialiser(this->x);
}
T x;
};
void init(int& x) {
x = 2;
}
// special case, initialise an int
template<> struct call_init<int>
{
void operator()(int& x) const {
init(x);
}
};
int main()
{
Foo<int> foo;
Foo<A::XX> foox;
Foo<B::YY> fooy;
std::cout << foo.x << std::endl;
return 0;
}
Your problem is also that intis not a class and no ADL is done for it, replacing int by custom class works:
template<typename T>
class Foo
{
public:
Foo() { init(x); }
T x;
};
struct C
{
int i = 0;
};
void init(C& c) { c.i = 42; }
Demo.
To allow to works for primitive type as int, you have to introduce some custom type:
template <typename> struct tag {};
template<typename T>
class Foo
{
public:
Foo() { init(x, tag<T>{}); }
T x;
};
void init(int& i, tag<int>) { i = 42; }
Demo
How can I do something like this? I want to create a object of class C and use parameters. To elaborate, the error here is the compiler reads this as a conversion, instead of me creating an object with parameters.
EDIT: for those who still don't understand, foobar is irrelevant. I've removed it as the error still occurs without the function.
// define foobar else where
template <class C>
class Dummy {
void foo(int bar) {
C dumdum = C(bar); // Error - '<function-style-cast>': cannot convert from initializer-list to 'C'
}
}
How does that help me?
You can make foo a function template that accepts a parameter pack to make it general.
Example program:
#include <iostream>
#include <sstream>
#include <string>
template <class C>
class Dummy {
public:
template <typename... Args>
void foo(Args... args ) {
foobar(C(args...));
}
};
struct Foo
{
Foo(int, int) {}
};
struct Bar
{
Bar(int) {}
};
struct Baz
{
};
void foobar(Foo)
{
std::cout << "In foobar(Foo)\n";
}
void foobar(Bar)
{
std::cout << "In foobar(Bar)\n";
}
void foobar(Baz)
{
std::cout << "In foobar(Baz)\n";
}
int main()
{
Dummy<Foo>().foo(10, 20);
Dummy<Bar>().foo(10);
Dummy<Baz>().foo();
}
Output:
In foobar(Foo)
In foobar(Bar)
In foobar(Baz)
Have you tried something like:
C dumdum(bar);
Or:
C dumdum{bar};
?
class C {
public:
C(int a) {}
};
template <class C>
class Dummy {
public:
void foo(int bar) {
C dumdum = C(bar);
}
};
int main() {
Dummy<C> dummy;
dummy.foo(2);
return 0;
}
I didn't see any errors.
I am using C++ and templates - but I need to allow using a member function for a specific type and prevent other types from using this function.
For example: I want this class to have print() for all types but have foo() for just type int. How can I do that ?
#include<iostream>
template <class type>
class example
{
private:
type data;
public:
void print(); // for all types
void foo(); // only for 'type' == int?
};
Factor the common, generic functionality into a base class. Specializations can inherit that.
namespace detail {
template <class type>
class example_base
{
private:
type data ;
public:
void print();
};
} // end namespace detail
template <class type>
struct example
: detail::example_base<type> {
using detail::example_base<type>::example_base; // inherit any constructors
};
template <> // specialize the class
struct example< int >
: detail::example_base<int> {
using detail::example_base<int>::example_base; // inherit any constructors
void other_function(); // extend the basic functionality
};
You can specify the template for some types. See this example :
template <typename T>
class MyClass
{
private:
double my_function() { return 1.0; }
};
template <>
class MyClass<double>
{
public:
double my_function() { return 2.0; }
};
int main()
{
MyClass<double> a;
MyClass<int> b;
double x = a.my_function(); // this works
// double y = b.my_function(); // not allowed
return 0;
}
Tested with GCC 4.7.2.
You could use std::enable_if and do something like this to obtain exactly what you want:
#include <iostream>
#include <type_traits>
template<class T>
class example
{
private:
T data;
public:
void print()
{
std::cout << " hello " << std::endl;
}
template<class U = T // make the function templated on U, but with default type T
, typename std::enable_if<std::is_integral<U>::value>::type* = nullptr // enable only for when U (T) is an integral type
>
void foo()
{
std::cout << " I will only compile when T is an integral type " << std::endl;
}
};
int main()
{
example<int> integer_example;
integer_example.print();
integer_example.foo(); // <--- compiles fine as int is integral
example<double> double_example;
double_example.print();
//double_example.foo(); // <--- will not compile
return 0;
}
In the std::enable_if you can also put std::is_same<U,int>::value instead of std::is_integral<U>::value to only allow the function only to be used for int and not other integral types.
I'm trying to write a template function, but I have trouble specializing it for vector<> and another class at the same time. Here is the code I'm using :
// template definition
template< class T >
void f( const T& value)
{
cout << "DEFAULT" << endl;
}
// specialization for MyClass
template< class T >
void f<> ( const MyClass & value )
{
cout << "MyClass" << endl;
}
// specialization for vector
template< class T >
void f<>( const std::vector<T> & v )
{
cout << "vector" << endl;
}
MyClass and MyClass2 are defined as:
class MyClass{
virtual void a() = 0;
};
class MyClass2 : public MyClass{
void a(){}
};
Finally, the main function:
int main(int nArgs, char *vArgs[]){
MyClass2 e;
f<MyClass>(e);
}
Here is the error I get when I try compiling it using Visual Studio 2010:
c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(869): error C2259: 'MyClass' : cannot instantiate abstract class
This seems to be very specific to this particular situation: As soon as I remove the const modifiers, I change the vector into a list or I make MyClass concrete, everything works. But for my problem I need for this particular situation to work.
Is anybody having the same error as me, and more importantly does anybody know a fix/workaround for this?
I believe this:
// specialization for vector
template< class T >
void f<>( const std::vector<T> & v )
{
cout << "vector" << endl;
}
is not possible (even if your syntax were corrected, as Anton did in his answer), because it is not a full specialization of f (there are unbound type parameters). Partial function specialization is not allowed under the C++ standard.
There are a few other questions on Stack Overflow involving similar code with similar issues. This one (and the winning answer) seems to be quite relevant: Why function template cannot be partially specialized?
You can peruse the C++ standards for yourself, if you were feeling particularly masochistic. You might start from section 14.7.3 ("Explicit specialization") at page 368 of this document: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf (which is a semi-recent draft, but not the most up to date. It is free, however.)
As other answers have indicated:
your syntax for specialization is wrong
you cannot partially specialize a template function
...does anybody know a fix/workaround for this?
Since you are using the template argument in the argument list, you can use overloaded functions.
template <class T>
void f(const T& value)
{
std::cout << "DEFAULT" << std::endl;
}
void f(const MyClass& value)
{
std::cout << "MyClass" << std::endl;
}
template <class T>
void f(const std::vector<T>& v) // this is an overload, not a specialization
{
std::cout << "vector" << std::endl;
}
int main()
{
f(1);
MyClass2 e;
f(e);
f(std::vector<int>());
}
You have mistakes in specialization syntax.
Probably, it should look like this:
// MyClass
class MyClass{
virtual void a() = 0;
};
class MyClass2 : public MyClass{
void a(){}
};
// template definition
template< class T >
void f(const T& value)
{
cout << "DEFAULT" << endl;
};
// specialization for MyClass
template<>
void f(const MyClass & value)
{
cout << "MyClass" << endl;
};
// specialization for vector of MyClass
template<>
void f(const std::vector<MyClass> & v)
{
cout << "vector" << endl;
}
int main()
{
// Using template for any type
f(2);
// Using specialization for MyClass
MyClass2 e;
f<MyClass>(e);
// Using specialization for vector<MyClass>
vector<MyClass> vM;
f(vM);
}
Can someone please explain me why is this not compiling...the specialized function of a specialized class ???
In the specialized version of the templated class the specialized function is not compiling.
#include<iostream>
using namespace std;
//Default template class
template<typename T>
class X
{
public:
void func(T t) const;
};
template<typename T>
void X<T>::func(T b) const
{
cout << endl << "Default Version" << endl;
}
//Specialized version
template<>
class X<int>
{
public:
void func(int y) const;
};
template<>
void X<int>::func(int y)
{
cout << endl << "Int Version" << endl;
}
int main()
{
return 0;
}
An explicit specialization of a class template is a concrete class, not a template, so you can (or rather, should) just write:
// template<>
// ^^^^^^^^^^
// You should not write this
void X<int>::func(int y) const
// ^^^^^
// And do not forget this!
{
cout << endl << "Int Version" << endl;
}
Thus leaving out the template<> part.
Also, mind the fact that your func() function is const-qualified in the declaration - so you have to use the const qualifier even in the defintion.
Here is a live example.
I think you left off the trailing const modifier