In C++, can you have a templated operator on a class? Like so:
class MyClass {
public:
template<class T>
T operator()() { /* return some T */ };
}
This actually seems to compile just fine, but the confusion comes in how one would use it:
MyClass c;
int i = c<int>(); // This doesn't work
int i = (int)c(); // Neither does this*
The fact that it compiles at all suggests to me that it's doable, I'm just at a loss for how to use it! Any suggestions, or is this method of use a non-starter?
You need to specify T.
int i = c.operator()<int>();
Unfortunately, you can't use the function call syntax directly in this case.
Edit: Oh, and you're missing public: at the beginning of the class definition.
You're basically right. It is legal to define templated operators, but they can't be called directly with explicit template arguments.
If you have this operator:
template <typename T>
T operator()();
as in your example, it can only be called like this:
int i = c.operator()<int>();
Of course, if the template argument could be deduced from the arguments, you could still call it the normal way:
template <typename T>
T operator()(T value);
c(42); // would call operator()<int>
An alternative could be to make the argument a reference, and store the output there, instead of returning it:
template <typename T>
void operator()(T& value);
So instead of this:
int r = c.operator()<int>();
you could do
int r;
c(r);
Or perhaps you should just define a simple get<T>() function instead of using the operator.
Aren't you thinking of
class Foo {
public:
template<typename T>
operator T() const { return T(42); }
};
Foo foo;
int i = (int) foo; // less evil: static_cast<int>(foo);
live example. This proves you do not need to specify the template argument, despite the claim in the accepted answer.
Related
In C++, can you have a templated operator on a class? Like so:
class MyClass {
public:
template<class T>
T operator()() { /* return some T */ };
}
This actually seems to compile just fine, but the confusion comes in how one would use it:
MyClass c;
int i = c<int>(); // This doesn't work
int i = (int)c(); // Neither does this*
The fact that it compiles at all suggests to me that it's doable, I'm just at a loss for how to use it! Any suggestions, or is this method of use a non-starter?
You need to specify T.
int i = c.operator()<int>();
Unfortunately, you can't use the function call syntax directly in this case.
Edit: Oh, and you're missing public: at the beginning of the class definition.
You're basically right. It is legal to define templated operators, but they can't be called directly with explicit template arguments.
If you have this operator:
template <typename T>
T operator()();
as in your example, it can only be called like this:
int i = c.operator()<int>();
Of course, if the template argument could be deduced from the arguments, you could still call it the normal way:
template <typename T>
T operator()(T value);
c(42); // would call operator()<int>
An alternative could be to make the argument a reference, and store the output there, instead of returning it:
template <typename T>
void operator()(T& value);
So instead of this:
int r = c.operator()<int>();
you could do
int r;
c(r);
Or perhaps you should just define a simple get<T>() function instead of using the operator.
Aren't you thinking of
class Foo {
public:
template<typename T>
operator T() const { return T(42); }
};
Foo foo;
int i = (int) foo; // less evil: static_cast<int>(foo);
live example. This proves you do not need to specify the template argument, despite the claim in the accepted answer.
I would like to have the following code in c++17:
#include <iostream>
#include <string>
#include <type_traits>
#include <functional>
class Foo;
template<class T>
class Bar {
public:
std::function<T(Foo&)> m_fn;
template<class Fn>
Bar(Fn fn) : m_fn(fn) {};
T thing(Foo &foo) const {
return m_fn(foo);
}
};
template<class Fn>
Bar(Fn) -> Bar<decltype(std::invoke(std::declval<Fn>(),
std::declval<Foo&>()))>;
class Foo {
public:
Foo() {};
template<class T>
std::vector<T> do_thing(const Bar<T> &b) {
std::vector<T> r;
r.push_back(b.thing(*this));
return r;
}
};
std::string test(Foo &) {
return "hello";
}
int main() {
Foo foo = Foo();
// works
std::vector<std::string> s = foo.do_thing(Bar{test});
// cant deduce T parameter to do_thing
std::vector<std::string> s = foo.do_thing({test});
}
But compiling this gives me "couldn't deduce template parameter âTâ" on the call to do_thing.
Having do_thing(Bar{test}) fixes this and works fine but equates to some ugly code in the real code equivalent. I would like to have do_thing({test}) or do_thing(test) implicitly construct a Bar and pass that as the argument if possible.
I also don't want to forward declare a variable to pass into do_thing either
Is there some way to guide the inference of template argument T so that the call to do_thing can stay clean?
Edit:
Sorry for the late edit, but the arguments to the Bar constructor are over simplified in the example I included. In reality, there is an extra parameter std::optional<std::string> desc = std::nullopt and that might change in the future (although unlikely). So constructing the Bar inside do_thing would be a bit hard to maintain...
would like to have do_thing({test}) or do_thing(test) implicitly construct a Bar and pass that as the argument if possible.
Unfortunately, when you call do_thing({test}) or do_thing(test), test (or {test}) isn't a Bar<T> object. So the compiler can't deduce the T type and can't construct a Bar<T> object.
A sort of chicken-and-egg problem.
The best I can imagine is to add, in Foo, a do_test() method as follows
template<typename T>
auto do_thing (T const & t)
{ return do_thing(Bar{t}); }
This way you can call (without graphs)
std::vector<std::string> s = foo.do_thing(test);
You get the same result as
std::vector<std::string> s = foo.do_thing(Bar{test});
-- EDIT --
The OP ask
is there any way of preserving the {test} brace syntax? maybe with initializer_list or something?
Yes... with std::initializer_list
template<typename T>
auto do_thing (std::initializer_list<T> const & l)
{ return do_thing(Bar{*(l.begin())}); }
but, this way, you accept also
std::vector<std::string> s = foo.do_thing(Bar{test1, test2, test3});
using only test1
Maybe a little better... another way can be through a C-style array
template <typename T>
auto do_thing (T const (&arr)[1])
{ return do_thing(arr[0]); }
This way you accept only an element.
This happens because {} is not an expression and can only be used in limited ways while doing argument deduction, the parameter must have specific forms in order to succeed.
The allowed parameters types that can be used to deduce template parameters when {} is involved are better expanded in [temp.deduct.call]/1, two of the examples extracted from the cited part of the standard are:
template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int
In your example the deduction guide is not used to deduce the T for {test} for the same as above.
foo.do_thing(Bar{test});
is your direct option without using additional functions.
I'm currently writing a template class for archiving (or serializing) and unarchiving data into/from a binary format. First off, I'm trying to close on what pattern I'll use. I am mostly inclined to using templates because unarchivers don't have an input type for method overloading. For instance, the following example is OK:
Archiver ar;
int i;
archive(ar, i);
But it's counterpart isn't:
Unarchiver unar;
int i;
i = unarchive(unar);
I would like to avoid using the function's name, such as unarchive_int because it would be troublesome when using templates. Say:
template <class T> class SomeClass
{
public:
void doSomething()
{
// Somewhere
T value = unarchive(unar);
}
};
This would make things messy, and as such I rather really use templates for this, whereas the previous expression would be T value = unarchive<T>(ar);. It also seems silly (arguably) to write a global function if either the first or only parameter are always the archiver and unarchiver objects; a template class seems to be in order:
template <class T> class Archiver
{
public:
void archive(T obj);
};
This works, but the archiving method always copies its input object. This is OK with POD data types, but not so much which classes. The solution seems obvious, and instead use a const reference as in void archive(const T & obj), but now it also seems silly to be passing integers, floats, and other PODs by reference. Although I would be happy with this solution, I tried to go a little further and have the object make the distinction instead. My first approach is std::enable_if, while assuming a copy by default (for all non-class members) and provide a class specialization where the archive method gets its input by reference instead. It doesn't work. Here's the code:
template <class T, class E = void>
class Archiver
{
public:
// By default, obj is passed by copy
void archive(T obj);
};
template <class T>
class Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::value>
{
public:
// I would expect this to be used instead if is_class<T> && !is_pod<T>
void archive(const T & obj);
};
The problem is that the second declaration is not visible at all to the compiler, and here's proof:
template <> void Archiver<std::uint8_t>::archive(uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
The former compiles fine, but the later gives:
out-of-line declaration of 'archive' does not match any declaration in
'Archiver<std::__1::basic_string<char>, void>'
On the other hand, if I get the std::string instead by copy if compiles just fine. I think I know why this happens, the compiler chooses the first template as it's generic enough for both declarations, but then how do I make it choose the more specialized version?
You want std::enable_if<...>::type, not std::enable_if<...>::value.
Here's a full demo:
#include <type_traits>
#include <cstdint>
#include <string>
template <class T, class E = void>
struct Archiver {
void archive(T obj);
};
template <class T>
struct Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::type>
{
void archive(const T & obj);
};
template <> void Archiver<std::uint8_t>::archive(std::uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
IIUC, the question boils down to how to define a generic template type that is optimized for calling functions.
For this, you can consider boost::call_traits, in particular, param_type:
template<typename T>
void foo(typename boost::call_traits<T>::param_type t);
Why doesn't this code compile?
template <class T>
class A
{
public:
A(T t) : t_(t) {}
private:
T t_;
};
int main()
{
A a(5.5);
// A<double> a(5.5); // that's what i don't want to do
}
I want template arguments to be implicit.
Like in this example:
template<class T>
T Foo(T t) { return t; }
// usage:
Foo(5.5);
UPDATE: named-constructor idiom isn't acceptable for me. I want to use this class for RAII.
The only way to do so is const A& a = A::MakeA(t), but it's ugly!
Since you have to name the type of a variable (C++03 can't infer the type of a variable), you can only do:
A<double> a(5.5); // that's what i don't want to do
The situation is a little easier when you needn't make a variable of the type, but want to pass it to some other function. In this case, you define an auxiliary "constructor function" (see std::make_pair):
template <class T>
A<T> make_a(T t) { return A<T>(t); }
and then use it like this:
another_function(make_a(1.1));
In C++0x, you will be able to do even
auto a(make_a(5.5));
to define your variable a.
However, inferring A's argument from its constructor is generally impossible, because you can't tell which specializations have the conversion constructor from a given type. Imagine there's a specialization
template <>
struct A<void>
{
A(double);
};
I am trying to write a code that calls a class method given as template parameter. To simplify, you can suppose the method has a single parameter (of an arbitrary type) and returns void. The goal is to avoid boilerplate in the calling site by not typing the parameter type. Here is a code sample:
template <class Method> class WrapMethod {
public:
template <class Object>
Param* getParam() { return ¶m_; }
Run(Object* obj) { (object->*method_)(param_); }
private:
typedef typename boost::mpl::at_c<boost::function_types::parameter_types<Method>, 1>::type Param;
Method method_;
Param param_
};
Now, in the calling site, I can use the method without ever writing the type of the parameter.
Foo foo;
WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar;
foo_bar.GetParam()->FillWithSomething();
foo_bar.Run(foo);
So, this code works, and is almost what I want. The only problem is that I want to get rid of the BOOST_TYPEOF macro call in the calling site. I would like to be able to write something like WrapMethod<Foo::Bar> foo_bar instead of WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar.
I suspect this is not possible, since there is no way of referring to a method signature other than using the method signature itself (which is a variable for WrapMethod, and something pretty large to type at the calling site) or getting the method pointer and then doing typeof.
Any hints on how to fix these or different approaches on how to avoid typing the parameter type in the calling site are appreciated.
Just to clarify my needs: the solution must not have the typename Param in the calling site. Also, it cannot call FillWithSomething from inside WrapMethod (or similar). Because that method name can change from Param type to Param type, it needs to live in the calling site. The solution I gave satisfies both these constraints, but needs the ugly BOOST_TYPEOF in the calling site (using it inside WrapMethod or other indirection would be fine since that is code my api users won't see as long as it is correct).
Response:
As far as I can say, there is no possible solution. This boil down to the fact that is impossible to write something like WrapMethod<&Foo::Bar>, if the signature of Bar is not known in advance, even though only the cardinality is necessary. More generally, you can't have template parameters that take values (not types) if the type is not fixed. For example, it is impossible to write something like typeof_literal<0>::type which evalutes to int and typeof_literal<&Foo::Bar>::type, which would evaluate to void (Foo*::)(Param) in my example. Notice that neither BOOST_TYPEOF or decltype would help because they need to live in the caling site and can't be buried deeper in the code. The legitimate but invalid syntax below would solve the problem:
template <template<class T> T value> struct typeof_literal {
typedef decltype(T) type;
};
In C++0x, as pointed in the selected response (and in others using BOOST_AUTO), one can use the auto keyword to achieve the same goal in a different way:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar = GetWrapMethod(&Foo::Bar);
Write it as:
template <typename Object, typename Param, void (Object::*F)(Param)>
class WrapMethod {
public:
Param* getParam() { return ¶m_; }
void Run(Object* obj) { (obj->*F)(param_); }
private:
Param param_;
};
and
Foo foo;
WrapMethod<Foo, Param, &Foo::Bar> foo_bar;
foo_bar.getParam()->FillWithSomething();
foo_bar.Run(foo);
EDIT: Showing a template function allowing to do the same thing without any special template wrappers:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param))
{
Param param;
param.FillWithSomthing();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar);
2nd EDIT: Modifying the template function to take the initialization function as a parameter as well:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param), void (Param::*init)())
{
Param param;
param.*init();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar, &Param::FillWithSomething);
If your compiler supports decltype, use decltype:
WrapMethod<decltype(&Foo::Bar)> foo_bar;
EDIT: or, if you really want to save typing and have a C++0x compliant compiler:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar= GetWrapMethod(&Foo::Bar);
EDIT2: Although, really, if you want it to look pretty you either have to expose users to the intricacies of the C++ language or wrap it yourself in a preprocessor macro:
#define WrapMethodBlah(func) WrapMethod<decltype(func)>
Have you considered using method templates?
template <typename T> void method(T & param)
{
//body
}
Now the compiler is able to implicitly determine parameter type
int i;
bool b;
method(i);
method(b);
Or you can provide type explicitly
method<int>(i);
You can provide specializations for different data types
template <> void method<int>(int param)
{
//body
}
When you are already allowing BOOST_TYEPOF(), consider using BOOST_AUTO() with an object generator function to allow type deduction:
template<class Method> WrapMethod<Method> makeWrapMethod(Method mfp) {
return WrapMethod<Method>(mfp);
}
BOOST_AUTO(foo_bar, makeWrapMethod(&Foo::Bar));
Okay let's have a go at this.
First of all, note that template parameter deduction is available (as noted in a couple of answers) with functions.
So, here is an implementation (sort of):
// WARNING: no virtual destructor, memory leaks, etc...
struct Foo
{
void func(int e) { std::cout << e << std::endl; }
};
template <class Object>
struct Wrapper
{
virtual void Run(Object& o) = 0;
};
template <class Object, class Param>
struct Wrap: Wrapper<Object>
{
typedef void (Object::*member_function)(Param);
Wrap(member_function func, Param param): mFunction(func), mParam(param) {}
member_function mFunction;
Param mParam;
virtual void Run(Object& o) { (o.*mFunction)(mParam); }
};
template <class Object, class Param>
Wrap<Object,Param>* makeWrapper(void (Object::*func)(Param), Param p = Param())
{
return new Wrap<Object,Param>(func, p);
}
int main(int argc, char* argv[])
{
Foo foo;
Wrap<Foo,int>* fooW = makeWrapper(&Foo::func);
fooW->mParam = 1;
fooW->Run(foo);
Wrapper<Foo>* fooW2 = makeWrapper(&Foo::func, 1);
fooW2->Run(foo);
return 0;
}
I think that using a base class is the native C++ way of hiding information by type erasure.