Error message with operator syntax, but not with function syntax - c++

Why am I getting an error message when calling unary + with operator syntax? If I call it with function syntax, it is OK. Live demo.
template <int size>
struct Buffer { char buf[size]; };
template <class T>
struct Wrapper { void operator+() {} };
Wrapper<Buffer<-5>> a;
void f1() { +a; } // error: Buffer<-5>::buf has negative size
void f2() { a.operator+(); } // OK

The unqualified lookup invokes ADL, which needs to know if there are any friend functions defined in the associated classes. Buffer<-5> is one such, so it is instantiated. The fact that it’s syntactically obvious that it declares no friends doesn’t change the fact that the check for same involves completing the class type, which fails.
As an example let's put Buffer into namespace N, and operator+ into Buffer. If a's type is Wrapper<N::Buffer<5>> (5 rarher than -5), operator+ is found by ADL, and the code compiles (live demo):
template <class T>
struct Wrapper {};
namespace N {
template <int size>
struct Buffer {
template <class T> friend void operator+(const Wrapper<T>&) {}
char buf[size];
};
}
Wrapper<N::Buffer<5>> a;
void f1() { return +a; }

Related

How to create specialization template using scope resolution operator in cpp

template<class t> class Temp{
static t x;
public:
Temp(){};
t increment();
~Temp(){/*body of destructor is important.*/};
};
template<class t>t Temp<t>::x;
template<class t> t Temp<t>::increment(){
return ++x;
}
/*Template specialization starts.*/
template<>class Temp<int>{
int x;
public:
Temp():x(0){};
int increment();
~Temp(){};
};
/*Below is the error part.*/
template<>int Temp<int>::increment(){
return 0;
}
The problem is the last block of code.
Compilation Error
->error: template-id 'increment<>' for 'int Temp::increment()' does not match any template declaration
You don't have to use template<> with specialized member function, because the compiler knows that you are specializing the Temp for int type. So an empty template<> giving the error.
int Temp<int>::increment() {
return ++x;
}
template is used to tell the compiler that T is template param, that's all. But in your case your are specializing for int type, so you don't have to specify template<>. template<> is applicable only for the class and not for member functions defining out side the class.

Template specialization within namespace

I was messing around with some code when this weird behavior occurred :
In the first test, base templated function, user and templated specialization lie within the same namespace and it behaves as I expect :
namespace Test1
{
template <typename V, typename T>
int doFoo(V& a_visitor, T& a_value)
{
return 0;
}
struct Foo
{
template <typename T>
int process(T const& a_value)
{
return doFoo(*this, a_value);
}
};
template <typename T>
int doFoo(Foo& a_vis, T const& a_ptr)
{
return 1;
}
}
int main()
{
int const k{ 42 };
return Test1::Foo{}.process(k); // returns 1
}
but when I move base templated function and its specialization in another namespace, the base one is selected :
namespace Test2
{
namespace b
{
template <typename V, typename T>
int doBar(V& a_visitor, T& a_value)
{
return 0;
}
}
struct Bar
{
template <typename T>
int process(T const& a_value)
{
return b::doBar(*this, a_value);
}
};
namespace b
{
template <typename T>
int doBar(Bar& a_vis, T const& a_ptr)
{
return 1;
}
}
}
int main()
{
int const k{ 17 };
return Test2::Bar{}.process(k); // returns 0
}
EDIT I can do even weirder : in example 1 if I replace call to doFoo with Test1::doFoo I get the wrong behavior again !
Could anyone explain me what is going on here ? How can I do if I really need struct Bar not to be within namespace b ?
To begin with, those aren't specializations, those are overloads. Completely different function templates that aren't related to each other.
The behavior you see is consistent with argument-dependent lookup. When encountering an unqualified function call, the compiler builds an overload set by examining the namespaces associated with each argument to the function call.
Normally this won't find declarations the come "after", but templates are special. In templates lookup for a dependent name, such as a function call that depends on a template parameter (the type of a_value), is performed after the template is instantiated, and not at the point of definition. That occurs in main, after the namespace is complete and all overloads are available, and so ADL finds the second overload.
This is also why when you qualify the call by Test1 you no longer find the second overload. That negates ADL, and only allows for overloads that appear prior to the point of the call. The easiest way to resolve it would probably be to delay the definition of process until all overloads are available, as other answers indicate.

avoid pointer-to-member-function for non-class type

I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.
template<typename T>
struct Foo
{
T val;
/** apply a free function */
template<typename U> Foo<U> apply(U(*fun)(const T&))
{
return Foo<U>(fun(val));
}
/** apply a member function */
template<typename U> Foo<U> apply(U (T::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
struct Bar{};
template class Foo<Bar>; // this compiles
//template class Foo<int>; // this produces an error
The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?
Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.
Using std::invoke instead helps, it is much easier to implement and read
template<typename T>
struct Foo
{
T val;
template<typename U> auto apply(U&& fun)
{
return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};
}
};
struct Bar{};
template class Foo<Bar>;
template class Foo<int>;
However, this won't compile if the functions are overloaded
int f();
double f(const Bar&);
Foo<Bar>{}.apply(f); // Doesn't compile
The way around that is to use functors instead
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); });
Which also makes it more consistent with member function calls
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); });
In order to remove the second overload you'd need to make it a template and let SFINAE work, e. g. like this:
template<typename T>
struct Foo
{
T val;
//...
/** apply a member function */
template<typename U, typename ObjT>
Foo<U> apply(U (ObjT::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
Alternatively, you could remove the second overload altogether, and use lambda or std::bind:
#include <functional> // for std::bind
template<typename T>
struct Foo
{
T val;
/** apply a member function */
template<typename U, typename FuncT>
Foo<U> apply(FuncT&& f)
{
return {f(val)};
}
};
struct SomeType
{
int getFive() { return 5; }
};
int main()
{
Foo<SomeType> obj;
obj.apply<int>(std::bind(&SomeType::getFive, std::placeholders::_1));
obj.apply<int>([](SomeType& obj) { return obj.getFive(); });
}
How can I effectively remove the second overload whenever T is a non-class type?
If you can use at least C++11 (and if you tried std::function I suppose you can use it), you can use SFINAE with std::enable_if
template <typename U, typename V>
typename std::enable_if<std::is_class<V>{}
&& std::is_same<V, T>{}, Foo<U>>::type
apply(U (V::*fun)() const)
{ return Foo<U>((val.*fun)()); }
to impose that T is a class.
Observe that you can't check directly T, that is a template parameter of the class, but you have to pass through a V type, a template type of the specific method.
But you can also impose that T and V are the same type (&& std::is_same<V, T>{}).

template friend function in another namespace and CRTP

This has been driving me crazy for the past couple hours, and I cannot seem to get around this problem. I have distilled the problem down to these 60 lines of code (including a main function).
#include <iostream>
namespace n1 {
// the general definition
template <class X, class Y> void f(X&, const Y&)
{
std::cout << "general template definition.\n";
}
} // namespace n1
namespace n2 {
// CRTP
template <class Derived> class A
{
int data;
// partial function template specialization for n1::f, and declare
// it a friend too, so that it may access the data attribute of A
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
}; // class A
} // namespace n2
namespace n1 {
// implementation for this particular function template specialization
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
{
std::cout << "partial template specialization: " << a.data << "\n";
}
} // namespace n1
namespace n2 {
// Another class!
class B : public A<B>
{
}; // class B
} // namespace n2
namespace n1 {
// --------------------
// tricky part is here!
// --------------------
template <class Y> void f(n2::B& b, const Y& y)
{
// FAIL! not a friend! How?
f(static_cast<n2::A<n2::B>&>(b), y);
}
} // namespace n1
int main()
{
n2::B b;
int x;
n1::f(b, x); // should print "partial template specialization"
return 0;
}
So, what I "want" is to have the compiler select my function template specialization of n1::f whenever it is invoked with a concrete subclass of A<Derived>. In order to make sure that the compiler favors my specialization, I need to supply, for every subclass (B in this case), also a template specialization for n1::f that simply delegates the call. When that happens, I expect the data member variable of A<Derived> to be accessible to n1::f, because I declare n1::f to be a friend of A<Derived>. However, GCC complains that A<Derived>::data is private and inaccessible, see this snippet on Coliru.
Is this construction possible? If so, how can I get around the compiler complaining that A<Derived>::data is not accessible? (Making it public is not an option).
Your class definition must look like this:
template <class Derived> class A
{
int data;
template <class D, class Y> friend void n1::f(A<D>& a, const Y& y);
};
In fact, function declaration is:
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
While your friend declaration is:
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
In this case, they are different beasts and that's why you receive that error. As you can see, template parameters lists are different. That's not a declaration of a function with a separated definition. They are two different function templates, one declared and the other one both declared and defined.
In other terms, in your code you are declaring a friend function but you never define it. On the other side, you introduced a free function template that cannot read the data member for it's private and the function isn't a friend one of A<Derived>.
See it running on wandbox.

Full class template specialization with forward declarations

It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.