Is it possible to supply template parameters when calling operator()? - c++

I'd like to use a template operator() but am not sure if it's possible. Here is a simple test case that won't compile. Is there something wrong with my syntax, or is this simply not possible?
struct A {
template<typename T> void f() { }
template<typename T> void operator()() { }
};
int main() {
A a;
a.f<int>(); // This compiles.
a.operator()<int>(); // This compiles.
a<int>(); // This won't compile.
return 0;
}

Like chris mentioned in the comments, no, not with the shorthand syntax. You must use the full .operator()<T>() syntax;

If you really want to use templated operator() and want to avoid writing constructions like a.operator()<int>(); you can add an auxiliary parameter to it:
template <typename T>
struct type{};
struct A
{
template<typename T>
void operator()(type<T>) { }
};
int main()
{
A a;
a(type<int>());
}
Live demo.
In C++14 you can even omit empty brackets in a(type<int>()); via a variable template:
template <typename T>
struct type_{};
template <typename T>
constexpr type_<T> type{};
struct A
{
template<typename T>
void operator()(type_<T>) { }
};
int main()
{
A a;
a(type<int>);
}
Live demo.

The exact syntax you want to use is not possible in the C++ language.
Depending on the real problem you're trying to solve (which isn't in the question), I can think of at least three options:
Use a named function instead of the operator.
Template A instead of the operator itself.
Use the verbose spelling to call the operator() (I'm not a big fan of this option).

Related

Why does C++20 not allow a concept declared nested in a class? [duplicate]

Consider this code:
struct A
{
template <typename T>
concept foo = true;
};
It doesn't compile. My Clang 10 gives me error: concept declarations may only appear in global or namespace scope, and GCC says something similar.
Is there a reason why it's not allowed? I don't see why it couldn't work, even if the enclosing class was a template.
The fundamental difficulty that would arise is that concepts could become dependent:
template<class T>
struct A {
template<T::Q X>
void f();
};
Is X a non-type template parameter of (dependent) type T::Q (which does not require typename in C++20), or is it a type template parameter constrained by the concept T::Q?
The rule is that it’s the former; we would need new syntax (along the lines of typename/template) to express the other possibility: perhaps something like
template<T::concept Q X> requires T::concept R<X*>
void A::g() {}
No one has explored such an extension seriously, and it could easily conflict with other extensions to concept syntax that might be more valuable.
The why is discussed in the answer by #DavisHerring. In this answer I want to share a pattern I was actually looking for when I encountered this question.
Depending on your use case, you maybe don't need the concept definition. If all you want to do is to avoid SFINAE trickery, you can directly invoke the requires clause and get rid of any concept at class scope:
struct A
{
template<typename T>
auto operator()(T t) const
{
if constexpr(requires { t.foo(); })
{
std::cout<<"foo"<<std::endl;
}
else
{
std::cout<<"no foo"<<std::endl;
}
}
};
and use that as
struct B { auto foo() {} };
struct C {};
int main()
{
A a;
a(B()); //prints "foo"
a(C()); //prints "no foo"
}
DEMO
However, if you find yourself using the same requires statement multiple times in your class, the original question why you just can't declare it once at class scope is justified.
Thus, in order to work around code duplication, you can declare a single static function which contains the concept you are looking for, e.g.
struct A
{
template<typename T>
static constexpr auto concept_foo(T t)
{
return requires{ t.foo(); };
}
template<typename T>
auto operator()(T t) const
{
if constexpr(concept_foo(t))
{
std::cout<<"foo"<<std::endl;
}
else
{
std::cout<<"no foo"<<std::endl;
}
}
};
This pattern could replace most use cases for concepts at class scope.

Overload operator [] with a template [duplicate]

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.

compile-time conditional member function call in C++

I have a template class for which certain member functions only make sense if the template parameters satisfy certain conditions. Using, for instance, std::enable_if<> I can define them only for these cases, but how can I call them conditionally? Here is a brief example
template<class T> class A
{
typename std::enable_if<std::is_floating_point<T>::value>::type a_member();
void another_member()
{
a_member(); // how to restrict this to allowed cases only?
}
};
Firstly, you can't use SFINAE like that - the template type parameter needs to be on the function, not the class.
A full solution looks like this:
template<class T> class A
{
private:
template <class S>
typename std::enable_if<std::is_floating_point<S>::value>::type a_member() {
std::cout << "Doing something";
}
template <class S>
typename std::enable_if<!std::is_floating_point<S>::value>::type a_member() {
//doing nothing
}
public:
void another_member()
{
a_member<T>();
}
};
int main() {
A<int> AInt;
AInt.another_member();//doesn't print anything
A<float> AFloat;
AFloat.another_member();//prints "Doing something"
}
WARNING: This is a complete, terrible hack that I have not tried that may never work.
Try adding this to the class declaration:
typename std::enable_if<std::is_floating_point<T>, int*>::type a_enabled_p() { return 0;};
void another()
{
if((a_enabled_p()+1)==1)
{
//Not enabled
}
else if((a_enabled_p()+1)==sizeof(int))
{
//Is enabled
}
}
Here's why this horror might work. If they are floating point, the return value of the predicate is an int*. If they are, there is no typedef, and it defaults to int (I hope). When you add 1 to an int*, you are really adding sizeof(int). Adding 1 to an int increments by one. That means that by checking the value of adding one, we know.
Note: Don't use this. It was fun to come up with, but the above answer is MUCH, MUCH
MUCH
Better. Don't use this. Please.

Switch passed type from template

Is it possible in C++ to check the type passed into a template function? For example:
template <typename T>
void Foo()
{
if (typeof(SomeClass) == T)
...;
else if (typeof(SomeClass2) == T)
...;
}
Yes, it is...but it probably won't work the way you expect.
template < typename T >
void foo()
{
if (is_same<T, SomeClass>::value) ...;
else if (is_same<T, SomeClass2>::value) ...;
}
You can get is_same from std:: or boost:: depending on your desire/compiler. The former is only in C++0x.
The problem comes with what is in .... If you expect to be able to make some function call specific to those types within foo, you are sadly mistaken. A compiler error will result even though that section of code is never run when you pass in something that doesn't obey that expected interface.
To solve THAT problem you need to do something a bit different. I'd recommend tag dispatching:
struct v1_tag {};
struct v2_tag {};
template < typename T > struct someclass_version_tag;
template < > struct someclass_version_tag<SomeClass> { typedef v1_tag type; };
template < > struct someclass_version_tag<SomeClass2> { typedef v2_tag type; };
void foo(v1_tag) { ... }
void foo(v2_tag) { ... }
template < typename T > void foo()
{
typedef typename someclass_version_tag<T>::type tag;
foo(tag());
}
Note that you will not be suffering any runtime-polymorphism overhead here and with optimizations turned on it should result in the same or even smaller code size AND speed (though you shouldn't be worrying about that anyway until you've run a profiler).
If you want to do something specific based on the type, specialize the template:
template <typename T>
void Foo() { }
template <>
void Foo<SomeClass>() { }
template <>
void Foo<SomeClass2>() { }
// etc.
(You don't actually want to specialize the function template, though; this is for exposition only. You'll either want to overload the template if you can, or delegate to a specialized class template. For more on why and how to avoid specializing function templates, read Herb Sutter's Why Not Specialize Function Templates?)
No, however you can use partial specialization :
template<typename T>
struct Bar { static void foo(); };
template<typename T>
template<> inline void Bar<T>::foo() {
//generic
}
template<> inline void Bar<int>::foo() {
//stuff for int
}
template<> inline void Bar<QString>::foo() {
//QString
}
Edit Yes with type traits, however it's not really needed.
Edit 2 type_traits example.
#include <type_traits>
template<typename T> void foo() {
using std::is_same;
if (is_same<T, T2>::value || is_same<T, T1>::value) {
/* stuff */
}
}
Yes. You will have to use type traits. For example:
#include <boost/type_traits/is_same.hpp>
template <typename T>
void Foo ()
{
if ((boost::is_same<T, SomeClass>::value))
...;
else if ((boost::is_same<T, SomeClass2>::value))
...;
}
Depending on what you are trying to achieve, using template specialization might be much better choice.
Also, you can use enable_if/disable_if to conditionally enable/disable certain functions/methods. Combining this with type traits will allow, for example, using one function for one set of types and another function for another set of types.

Function template with an operator

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.