concept to check existence of function in class (problem in GCC?) - c++

I would like to detect if a function (operator() in my case) is present in a class, regardless of its signature or whether it would be possible to get a pointer to it (may be impossible without additional info because it is templated or overloaded). The following code using a concept compiles on MSVC and clang, but not GCC (see godbolt link below for error messages). Is this supposed to work and is GCC not conformant, or is this not supposed to work and are MSVC and clang too lenient? It is interesting to note GCC fails not only for the overloaded and templated operator()s, but also for the simple functor.
Note also that while the example code uses variations on unary functions taking an int, I'd like the concept to work regardless of function signature (and its does for MSVC and clang).
Try here for GCC, clang and MSVC.
Context is making this work, it does now on MSVC and clang, but not GCC.
template <typename C>
concept HasCallOperator = requires(C t)
{
t.operator();
};
struct functor
{
int operator()(int in_)
{ return 1; }
};
struct functorOverloaded
{
int operator()(const int& in_)
{ return 1; }
int operator()(int&& in_)
{ return 1; }
};
struct functorTemplated
{
template <typename... T>
int operator()(const T&... in_)
{ return 1; }
};
template<HasCallOperator T>
struct B {};
int main()
{
B<functor> a;
B<functorOverloaded> b;
B<functorTemplated> c;
}

First, the way to check a concept is just to static_assert (not to try to instantiate a constrained class template).
static_assert(HasCallOperator<functor>);
static_assert(HasCallOperator<functorOverloaded>);
static_assert(HasCallOperator<functorTemplated>);
Second, you can't write t.operator() for the same reason that you can't write f.fun for any other non-static member function: if you do class member access, it must end with invocation. So this is simply a clang/msvc bug that it allows any of this.
And then &C::operator() will not work if the call operator is overloaded or a function template (or both).
Which really calls into question the whole point of this, since without reflection we're highly limited in the kinds of answers we can give to these questions. You can really only address the simple case of non-overloaded, non-template call operator.
Nevertheless, there is an approach that works here. The trick is the same problem we have in our present case: &C::operator() doesn't work if operator() is overloaded.
So what we do instead is construct a case where &C::operator() would be overloaded if there were one, and invert the check. That is:
#include <type_traits>
struct Fake { void operator()(); };
template <typename T> struct Tester : T, Fake { };
template <typename C>
concept HasCallOperator = std::is_class_v<C> and not requires(Tester<C> t)
{
&Tester<C>::operator();
};
HasCallOperator<C> doesn't check C, it checks a type that inherits from both C and a type that has a non-overloaded non-template call operator. If &Tester<C>::operator() is a valid expression, that means it refer to &Fake::operator(), which means that C did not have one. If C had a call operator (whether it's overloaded or a template or both or neither), then &Tester<C>::operator() would be ambiguous.
The is_class_v check is there to ensure that stuff like HasCallOperator<int> is false rather than ill-formed.
Note that this won't work on final classes.

Related

Templated constructor ambiguity when calling overloaded function with castable type

I have 2 classes that both have single-argument templated constructors. One is meant as a catch all for integer types, and in the other class it's for binding any iterable object. I have two overloads for a particular function that will each of these types. If I call the function with an integer type or a string, or something that would work for at least one of the classes, I get an error about call ambiguity.
#include <string>
class A {
public:
template <typename Iterable>
A(Iterable it) : s(it.begin(), it.end()) {}
private:
std::string s;
};
class B {
public:
template <typename Integer>
B(Integer i) : i(i + 1) {}
private:
int i;
};
void Use(A a)
{
// some thing
}
void Use(B b)
{
// some other thing
}
int main(void)
{
Use(0);
return 0;
}
The compiler doesn't seem to be looking far enough into the set of polymorphisms to determine that there really only is one possible solution. Could this be because template are 'resolved' before function overloads? How do I give the compiler some help?
The compiler doesn't seem to be looking far enough into the set of polymorphisms to determine that there really only is one possible solution.
Note that overload resolution is performed based on the signature of function templates, including function names, function parameters, template parameters, etc; but not implementations (e.g. the function body), which won't be examined during overload resolution.
You could apply SFINAE to put restrictions on types which could be accepted by constructor templates, by adding another template parameter with default value. e.g.
template <typename Iterable, typename = std::void_t<decltype(std::declval<Iterable>().begin()),
decltype(std::declval<Iterable>().end())>>
A(Iterable it) : s(it.begin(), it.end()) {}
and
template <typename Integer, typename = std::void_t<decltype(std::declval<Integer>() + 1)>>
B(Integer i) : i(i + 1) {}
LIVE
The compiler doesn't regard the implementation of the method when follows the SFINAE rules. In other words it sees the declaration of the class A constrator that accepts a single argument.
If you wish SFINAE to eliminate this choice, you need to move the expression that fails the substitution to the function signature.

Detect template parameter type [duplicate]

In my template-ized function, I'm trying to check the type T is of a specific type. How would I do that?
p/s I knew the template specification way but I don't want to do that.
template<class T> int foo(T a) {
// check if T of type, say, String?
}
Thanks!
Instead of checking for the type use specializations. Otherwise, don't use templates.
template<class T> int foo(T a) {
// generic implementation
}
template<> int foo(SpecialType a) {
// will be selected by compiler
}
SpecialType x;
OtherType y;
foo(x); // calls second, specialized version
foo(y); // calls generic version
If you don't care about compile-time, you may use boost::is_same.
bool isString = boost::is_same<T, std::string>::value;
As of C++11, this is now part of the standard library
bool isString = std::is_same<T, std::string>::value
hmm because I had a large portion of
same code until the 'specification'
part.
You can use overloading, but if a large part of the code would work for any type, you might consider extracting the differing part into a separate function and overload that.
template <class T>
void specific(const T&);
void specific(const std::string&);
template <class T>
void something(const T& t)
{
//code that works on all types
specific(t);
//more code that works on all types
}
I suppose you could use the std::type_info returned by the typeid operator
I suspect someone should tell you why it might not be a good idea to avoid using overloading or specialization. Consider:
template<class T> int foo(T a) {
if(isAString<T>()) {
return a.length();
} else {
return a;
}
}
You might think on a first sight that it will work for int too, because it will only try to call length for strings. But that intuition is wrong: The compiler still checks the string branch, even if that branch is not taken at runtime. And it will find you are trying to call a member function on non-classes if T is an int.
That's why you should separate the code if you need different behavior. But better use overloading instead of specialization, since it's easier to get a clue how things work with it.
template<class T> int foo(T a) {
return a;
}
int foo(std::string const& a) {
return a.length();
}
You have also better separated the code for different paths of behavior. It's not all anymore clued together. Notice that with overloading, the parameters may have different type forms and the compiler will still use the correct version if both match equally well, as is the case here: One can be a reference, while the other can not.
You can check using type_traits (available in Boost and TR1) (e.g. is_same or is_convertible) if you really want to avoid specialization.
You can perform static checks on the type that you have received (look at the boost type traits library), but unless you use specialization (or overloads, as #litb correctly points out) at one point or another, you will not be able to provide different specific implementations depending on the argument type.
Unless you have a particular reason (which you could add to the question) not to use the specialization in the interface just do specialize.
template <> int subtract( std::string const & str );
If you are using C++11 or later, std::is_same does exactly what you want:
template <typename T>
constexpr bool IsFloat() { return std::is_same<T, float>::value; }
template <typename T>
void SomeMethodName() {
if (IsFloat<T>()) {
...
}
}
http://en.cppreference.com/w/cpp/types/is_same

May a member function template specialization have a different access level than the main template?

An answer to a a question I had about deleting functions mentioned how member function templates can't be specialized at class scope. That led me to wonder if it's possible for a member function template specialization to have a different access level than the main template. In the code below, I'm trying to have a private specialization of a public member function template:
#include <iostream>
class Foo {
public:
template<typename T>
void func(T) { std::cout << "Public\n"; }
private:
template<>
void func<char>(char) { std::cout << "Private\n"; }
friend int main();
};
int main()
{
Foo f;
f.func(10);
f.func('a');
}
With the latest MSVC, this compiles, runs, and produces the expected output:
Public
Private
With g++ 4.8 and Clang 3.2, the code is rejected. Clang says this:
error: explicit specialization of 'func' in class scope
void func<char>(char) { std::cout << "Private\n"; }
^
Presumably g++ and Clang are using 14.7.3/2 of C++11 as the basis for their behavior, but I think there might be a little wiggle room, because 3.3.6/3 says that the global scope is a namespace, and the global namespace (indirectly) encloses the template specialization.
My question isn't about these parts of the Standard or about any of these compilers' behaviors, though, it's about whether it is possible for a member function template to have a specialization that has a different access level than the general template. For example, is it possible to have a public member function template and a private specialization of that template?
We can always do it manually.
Some random SFINAE machinery:
#include <iostream>
#include <utility>
#include <type_traits>
template<typename T> constexpr bool IsInt() { return std::is_same<T,int>::value; }
template<std::size_t>
struct SecretEnum {
enum class hidden {};
};
template<bool b, int i=1> using EnableIf = typename std::enable_if<b,typename SecretEnum<i>::hidden>::type;
class Foo {
public:
template<typename T, EnableIf< !IsInt<T>(), 1 >...>
void func(T) { std::cout << "Public\n"; }
private:
template<typename T, EnableIf< IsInt<T>(), 2 >...>
void func(T) { std::cout << "Private with int\n"; }
friend int main();
};
int main()
{
Foo f;
f.func(10);
f.func('a');
}
now this trick does not work with clang because of how I did the SFINAE and method distinguishing last I checked. But that can be replaced with other similar tricks (like pointer based default arguments in the second argument -- replace EnableIf< IsInt<T>(), 2 >... with EnableIf< IsInt<T>(), 2 >* = nullptr or somesuch for clang. I just find it less appealing.)
So what is going on above? I have two different overloads for func. Both are template functions with one argument that is a T, and a pack of some secret enum whose type is valid if and only if T matches the IsInt<T>() or !IsInt<T>() test respectively. The type of the packs differ in the two cases (one if them is SecretEnum<2>::hidden, the other is SecretEnum<1>::hidden), so their signatures are sufficiently different to satisfy most C++11 compilers (clang considers them to be identical last I checked, generating errors, I believe clang is wrong).
When you invoke func<blah>, it checks to see which (if any) of the two func are appropriate. As their conditions are exact opposites of each other, only one of them is ever the proper one.
In effect, we are doing manual specialization.
In C++1y, we may be able to template<IsInt T> and template<IsNotInt T> if the stars align properly and the concepts lite that gets into the technical report lets this work.

Template by method pointer in clang vs gcc and msvc

I have this function:
template <typename T, void (T::*pf)()>
void call(T& t)
{
(t.*pf)();
}
If I have class foo with a method with the appropriate signature (say bar) I can call it like this call<foo, &foo::bar>(); and it's fine. However if bar is const gcc and msvc are happy to compile it when called like this call<const foo, &foo::bar>(). Clang complains that the second template parameter is invalid. When I put const in the template arguments (void (T::*pf)() const) all tree compile it.
Now, this is not a huge issue, but my code becomes much much cleaner if I don't have to write this wretched const in the template arguments.
So the question basically is: What does the standard say about this? Is this a clang bug or are gcc and msvc just letting it slide because they're cool like that?
PS Here's a link to a complete repro program: http://codepad.org/wDBdGvSN
The const-ness of a method is part of the 'signature' of it. So, the proper way to define and use a pointer to member is:
R (Obj::*)(Args) // for non-const member
R (Obj::*)(Args) const // for const member
Note that a const member can be called on a non-const object, which is not the case with R (const Obj::*)(Args).
A way to solve this is to abstract such function pointers, by defining 'call wrappers':
template<typename O, void (O::* f)()>
struct NonConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
template<typename O, void (O::* f)() const>
struct ConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
Then, you can use it the following way (here the abstraction takes place):
template<typename Obj, typename Function>
void call(Obj* o)
{
Function::call(o);
}
There is a live example here.
This is just the main idea. You can extend it with automatic detection of whether the method is const or not, without changing the user code.

How do I check my template class is of a specific classtype?

In my template-ized function, I'm trying to check the type T is of a specific type. How would I do that?
p/s I knew the template specification way but I don't want to do that.
template<class T> int foo(T a) {
// check if T of type, say, String?
}
Thanks!
Instead of checking for the type use specializations. Otherwise, don't use templates.
template<class T> int foo(T a) {
// generic implementation
}
template<> int foo(SpecialType a) {
// will be selected by compiler
}
SpecialType x;
OtherType y;
foo(x); // calls second, specialized version
foo(y); // calls generic version
If you don't care about compile-time, you may use boost::is_same.
bool isString = boost::is_same<T, std::string>::value;
As of C++11, this is now part of the standard library
bool isString = std::is_same<T, std::string>::value
hmm because I had a large portion of
same code until the 'specification'
part.
You can use overloading, but if a large part of the code would work for any type, you might consider extracting the differing part into a separate function and overload that.
template <class T>
void specific(const T&);
void specific(const std::string&);
template <class T>
void something(const T& t)
{
//code that works on all types
specific(t);
//more code that works on all types
}
I suppose you could use the std::type_info returned by the typeid operator
I suspect someone should tell you why it might not be a good idea to avoid using overloading or specialization. Consider:
template<class T> int foo(T a) {
if(isAString<T>()) {
return a.length();
} else {
return a;
}
}
You might think on a first sight that it will work for int too, because it will only try to call length for strings. But that intuition is wrong: The compiler still checks the string branch, even if that branch is not taken at runtime. And it will find you are trying to call a member function on non-classes if T is an int.
That's why you should separate the code if you need different behavior. But better use overloading instead of specialization, since it's easier to get a clue how things work with it.
template<class T> int foo(T a) {
return a;
}
int foo(std::string const& a) {
return a.length();
}
You have also better separated the code for different paths of behavior. It's not all anymore clued together. Notice that with overloading, the parameters may have different type forms and the compiler will still use the correct version if both match equally well, as is the case here: One can be a reference, while the other can not.
You can check using type_traits (available in Boost and TR1) (e.g. is_same or is_convertible) if you really want to avoid specialization.
You can perform static checks on the type that you have received (look at the boost type traits library), but unless you use specialization (or overloads, as #litb correctly points out) at one point or another, you will not be able to provide different specific implementations depending on the argument type.
Unless you have a particular reason (which you could add to the question) not to use the specialization in the interface just do specialize.
template <> int subtract( std::string const & str );
If you are using C++11 or later, std::is_same does exactly what you want:
template <typename T>
constexpr bool IsFloat() { return std::is_same<T, float>::value; }
template <typename T>
void SomeMethodName() {
if (IsFloat<T>()) {
...
}
}
http://en.cppreference.com/w/cpp/types/is_same