Potential g++ template bug? - c++

I've encountered some code which I think should compile, but doesn't. So I'm hoping some of the local standards experts here at SO can help :-).
I basically have some code which resembles this:
#include <iostream>
template <class T = int>
class A {
public:
class U {
};
public:
U f() const { return U(); }
};
// test either the work around or the code I want...
#ifndef USE_FIX
template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
#else
typedef A<int> AI;
bool operator==(const AI::U &x, int y) {
return true;
}
#endif
int main() {
A<int> a;
std::cout << (a.f() == 1) << std::endl;
}
So, to describe what is going on here. I have a class template (A) which has an internal class (U) and at least one member function which can return an instance of that internal class (f()).
Then I am attempting to create an operator== function which compares this internal type to some other type (in this case an int, but it doesn't seem to matter).
When USE_FIX is not defined I get the following error:
test.cc: In function 'int main()':
test.cc:27:25: error: no match for 'operator==' in 'a.A<T>::f [with T = int]() == 1'
Which seems odd, because I am clearly (I think) defining a templated operator== which should cover this, in fact if I just do a little of the work for the compiler (enable USE_FIX), then I no longer get an error. Unfortunately, the "fix" doesn't work generically, only for a specific instantiation of the template.
Is this supposed to work as I expected? Or is this simply not allowed?
BTW: if it matters I am using gcc 4.5.2.

The problem with const typename A<T>::U &x is that U is a dependent type and the compiler cannot deduce T from the argument (this is one of the nondeduced context).
You could, for example, have two specializations of A:
class X { };
class Y { };
class Z { };
template <> class A<X> {
public:
typedef Z U;
};
template <> class A<Y> {
public:
typedef Z U;
};
If you then call:
Z a;
a == 1;
what should the compiler deduce T as? X? Y?
One solution in this particular case is to declare operator== as a nontemplate friend inside of the class template:
template <class T = int>
class A {
public:
class U {
};
friend bool operator==(const U& x, int y) {
return true;
}
public:
U f() const { return U(); }
};

template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
Using this template, it is not permissible (or sometimes possible) to deduce the template parameter T from the type of x. It is what is known as a non-deducible context. (E.g. Somebody could specialize A for a different parameter, say double and make A<double>::U a typedef for A<int>::U.)
There is no workaround, you would have to explicitly specify the template parameter which for operator== makes for ugly syntax.

It is not allowed for rather obvious reasons. In general case there's really no way the compiler can deduce the template argument from your call to operator ==. Apparently you assumed that the nested type U uniquely defines the enclosing A specialization. That is not true, which can be illustrated by the following example with two explicit specializations of A
template <> class A<int> {
public:
class U {};
};
template <> class A<double> {
public:
typedef A<int>::U U;
};
In this case, if you call templated operator == with an argument of type A<int>::U the compiler cannot deduce template argument T for templated operator ==. Should T be int or double? There's no way to say.
In order to avoid these ambiguities such situations are called non-deduced contexts. Deducing the enclosing class template arguments from a nested type is an example of non-deduced context.

Related

SFINAE not working with member function of template class

I have a template class where I would like to remove a member function if the type satisfies some condition, that, as far as I understand, should be a very basic usage of SFINAE, for example:
template<class T>
class A
{
public:
template<typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
T foo () {
return 1.23;
}
};
However, this is results in an error "no type named 'type'", like SFINAE was not going on. This however works if foo is a function not member of a class. What is wrong with this implementation?
You're missing a dependent name for the compiler to use for SFINAE. Try something like this instead:
#include <type_traits>
template<class T>
class A
{
public:
template<typename Tp = T>
typename std::enable_if<std::is_floating_point<Tp>::value, Tp>::type
foo () {
return 1.23;
}
};
int main() {
A<double> a;
a.foo();
}
If the type T is not floating point, the declaration would be malformed (no return type) and the function would not be considered for the overload set.
See it on godbolt.

Does the c++ friend keyword mean more then access to private?

I wrote simple class and define one copy constructor.
Then add friend equal comparison operator and compare int with Int
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
friend bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
};
int main() {
int a;
Int<int> x(a);
x == a;
}
Compiled successfully.
If I turn the friend bool operator==(const Int<T>& f, const Int<T>& s); into a non-friend template. I get a compiler error:
error: no match for 'operator==' (operand types are 'int' and 'Int<int>'
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
template <class T>
bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
int main() {
int a;
Int<int> x(a);
x == a;
}
Does it mean that friend functions allow specific conversions?
5 == x works too.
Does the c++ friend keyword mean more then access to private?
Depending on context, it can have more implications, yes. For instance, a friend function defined inline, with no other declaration, can only be found by argument dependent lookup, even though it's a member of the enclosing namespace:
namespace foo {
struct bar {
friend void baz(bar const&) {}
};
}
int main() {
foo::bar bar;
// foo::baz(bar); // ill-formed, no member baz in foo
baz(bar); // Okay, it *can* be found by ADL
};
That is not directly related to your question, but that is how the friend operator== is looked up. And that said friend is also not a template itself. When you instantiate Int<int>, this "injects" a free operator== function - which is, again, not a template - into the namespace Int is a member of. When that operator function is looked up (by ADL) for the purposes of doing x == a, the compiler will happily consider implicitly converting a to Int<int>, because we can do implicit conversions to match regular free functions.
And speaking of conversions...
I wrote simple class and define one copy constructor.
You did not. That is a user-defined constructor taking an int const& argument, not an Int<int> const& like a copy constructor would take. You defined a converting constructor (because it's not explicit), which is exactly how the compiler can convert a to Int<int> above.
If I turn...
In your second version the operator is a template. It's still looked up by ADL. But template argument deduction only considers the exact type of the arguments. I.e, both arguments to operator== must be directly able to bind to Int<T> const& for some T. An int cannot be bound directly to Int<int> const&, it requires a conversion. So it doesn't match the sort of argument the template needs to do template argument deduction. Therefore the template cannot be instantiated, and is not a candidate.
Does it mean that friend functions allows specific conversions?
No, it's not the friendship. It's the template vs non-template business. You can define an operator== without friendship, but it has to be per-instantiation of Int:
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
bool operator==(const Int<int>& f, const Int<int>& s) {
return f.value == s.value;
}
That will make your main well-formed too. But as you noticed, it's not very useful having to declare those individually, so many code bases will use the friend version to "inject" this free function automatically.

C++ Template: typename and function to map to int

I'm writing a C++ template that needs two params: typename T, and an arbitrary function that maps T to an unsigned int.
How can I declare and use a template that can do that? I'd like to keep it simple, so that any dumb function can be used.
UPDATE:
Here is an example of what I'd like to do:
template<typename T, function f> // f has signature: unsigned int f(T);
class SortedContainer {
...
}
And, in this file:
unsigned int weight(Package p) { return p.w; }
SortedContainer<Package, &weight> sc;
UPDATE upon writing code
Based on the answers, I tried writing code, but it won't compile. Or rather, the template will compile, but not the test which invokes it.
The template code looks like this:
template<typename T, typename f>
class C {
...f(T)...
...
The invocation code looks like:
struct S {
int operator()(const int n) {
return n; // Dummy test code
}
};
...C<int, S>&...
The error message is:
error: no matching function for call to 'S::S(const int&)'
note: candidates are:
note: S::S()
It seems like it's trying to use S's constructor for some reason, as opposed to using the operator() which I want it to do.
The purpose of the f parameter is that the SortedContainer needs to be able to position T by an integer value. T is not necessarily an integer or even Comparable, so the caller, when instantiating a SortedContainer, needs to pass not only type T, but a function f to transform T to an integer.
The common way of doing this is to accept a general type F for the function. This will allow any kind of function-like object, whether it is a function pointer or a class object with an overloaded operator(). So:
template<class T, class F>
class SortedContainer {
// ...
}
Compare with things like std::map which does exactly this.
The disadvantage of this is that you cannot control what the prototype of the function is. This may or may not be a problem. One way is just to use it as if it was T-to-unsigned int and rely on the fact that the type system will catch any errors at the point of use.
Another way would be to verify the constraint with some kind of type trait. An example:
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
Edit: I wrote a small example to convince myself i got the assert right, might as well post it. Here, using A will compile OK but B will fail the assertion.
#include <type_traits>
template<class T, class F>
class SortedContainer {
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
};
struct A {
unsigned int operator()(double) { return 0; }
};
struct B {
double operator()(double) { return 0; }
};
int main() {
SortedContainer<double, A> a;
SortedContainer<double, B> b;
}
Based on your other edit:
Note that the templated type F only captures the type of the function. You still need an object of this type - the actual function - to call. Again, compare with std::map which first is templated to take a comparator type, and then has a constructor that takes an object of this type. This is true even if you use a normal function - the type will be SortedContainer<T, unsigned int (*)(T)>, but you would somehow need to pass the actual function pointer into the container (probably through the constructor).
Something like this:
template<class T, class F>
class SortedContainer {
public:
SortedContainer(F f = F()): func(f) {}
void foo() {
// ...
func();
// ...
}
private:
F func;
};
struct A {
unsigned int operator()() { return 0; }
};
int main() {
A a;
SortedContainer<double, A> c(a);
c.foo();
}
IMO, you don't require a separate template argument for Function F.
template<typename T> // F not required!
class SortedContainer {
...
};
Choose a good name and use that function by overloading it for various cases. e.g. to_uint()
Since you want to map (i.e. relate) a type to an unsigned int (uint), use following function in global scope:
template<typename T>
uint to_uint (const T& t) {
return t.to_uint(); // Must have `uint to_uint() const` member, else error
}
// Overloads of `to_uint()` for PODs (if needed)
template<typename T> // For all kinds of pointers
uint to_uint (const T* const pT) {
if(pT == nullptr)
<error handling>;
return to_uint(*pT);
}
Scenario: For Sorted_Container<X>, whenever to_uint(x) is invoked, then:
If X is a class, then it must have uint to_uint() const method
Else if X is a POD, then you may have to overload to_uint() for that type
Else, the compiler will generate an error
It's as you said, pretty much:
template< typename T, unsigned int f(T) >
struct SortedContainer;
...
SortedContainer<Package, weight> sc;
if you actually wanted the argument to be a function pointer rather than a function,
template< typename T, unsigned int (*f)(T) >
and similarly if you want the argument to be a function reference.
(naturally, this will only work for dumb functions, not for function objects with an operator() operator of the right signature)
You may use C-style function pointers as #Hurkyl suggests, or std::function which probably can't be template parameters, but I think that idea is wrong.
C++ templates are duck-typed, so STL code in many places (std::unordered_map -> std::hash, std::sort -> std::less) relies on that. I think you should also apply this approach - just ask user to provide specialization for type T:
/* Universal implementation */
template<typename T>
unsigned int sorted_container_weight(T t) { return t; }
template<typename T>
class SortedContainer {
T t;
public:
unsigned int somefunc() {
return sorted_container_weight(t);
}
};
template<>
unsigned int sorted_container_weight<Package>(Package p) { return p.w; }
SortedContainer<Package> sc;

How to deduce class type from method type in C++ templates?

In templates as shown below, I would like the call Run(&Base::foo) succeed without the need to name the Base type twice (as is done in the compiling Run<Base>(&Base::foo) call). Can I have that? Possibly without adding a ton of Boost headers?
With the provided code, I get an error of:
prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’
(you can fiddle with the snippet at http://ideone.com/8NZkq):
#include <iostream>
class Base {
public:
bool foo() { return true; }
};
Base* x;
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
T* y = dynamic_cast<T*>(x);
std::cout << (y->*check)();
}
int main() {
Base y;
x = &y;
Run<Base>(&Base::foo);
Run(&Base::foo); // why error?
}
The T in Traits<T>::BoolMethodPtr is in a non-deduced context, so the compiler will not deduce automatically from the call what type T should be.
This is because there could be code like this:
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<>
struct Traits<int> {
typedef bool (Base::*BoolMethodPtr)();
};
Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */
If you can do without the Traits<T> class, you can write Run as:
template<class Class>
void Run(bool (Class::*check)()) {
Class* y = dynamic_cast<Class*>(x);
std::cout << (y->*check)();
}
In this context, Class can be deduced to mean Base
To pick apart a type, any type, use partial specialization. There is no function template partial specialization, so you'll need to directly parameterize the function on its argument type and retrieve the class type inside.
template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this
template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
typedef C host;
typedef void sfinae; // disallow function for non ptmf arguments
};
template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
typedef T BoolMethodPtr; // or something
typedef typename get_host_class< T >::host host;
}
I think this is a non deduced context.
$14.8.2.5/5- "The non-deduced contexts
are: — The nested-name-specifier of a
type that was specified using a
qualified-id."
I think this is the quote that applies in this case. But some template gods need to ratify my understanding.
When the compiler tries to match a template argument, it only considers the primary class type. In other words, when it encounters the expression:
Run(&Base::foo);
...and it's trying to figure out the template parameter for Run, it only considers the type of foo itself, and doesn't consider whatever class foo is a part of.
EDIT:
And the type of foo is bool(Base::*)(void), but what you want the compiler to find is just Base

C++ template arguments in constructor

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);
};