Following and example I took from another question, I understand why this does not work:
struct Foo {
Foo() {}
Foo(int) {}
Foo operator+(Foo const & R) { return Foo(); }
};
struct Bar {
Bar() {}
Bar(int) {}
};
Bar operator+(Bar const & L, Bar const & R) {
return Bar();
}
int main() {
Foo f;
f+1; // Will work - the int converts to Foo
1+f; // Won't work - no matching operator
Bar b;
b+1; // Will work - the int converts to Bar
1+b; // Will work, the int converts to a Bar for use in operator+
}
But then, if I change it to use templates in this way:
template <class T>
struct Foo {
Foo() {}
Foo(T) {}
Foo operator+(Foo const & R) { return Foo(); }
};
template <class T>
struct Bar {
Bar() {}
Bar(T) {}
};
template <class T>
Bar operator+(Bar const & L, Bar const & R) {
return Bar();
}
int main() {
Foo<int> f;
f+1; // Will work - the int converts to Foo
1+f; // Won't work - no matching operator
Bar<int> b;
b+1; // DOES NOT WORK
1+b; // DOES NOT WORK
}
It does not work. Can anyone put some light on this? Templates are driving me crazy.
Thanks.
There are two problems.
You need to add the template type to the arguments in the definition of the operator. This is necessary because it needs to use them to know which instantiation of Bar to use.
If you want mixed operators (that operate on two separate types) in a template function, you're going to need to provide the definitions for all of the mixed cases. Otherwise, the template deduction system won't work the way you want.
.
template <class T>
Bar<T> operator+(Bar<T> const & L, Bar<T> const & R) { // Fixed
return Bar<T>();
}
template <class T>
Bar<T> operator+(Bar<T> const & L, const T & R) { // Added
return L + Bar<T>(R);
}
template <class T>
Bar<T> operator+(const T& L, Bar<T> const & R) { // Added
return Bar<T>(L) + R;
}
There's no implicit conversion between int and Bar, only between int and Bar<int>. In fact, you haven't defined a type Bar; instead, you have a family of types Bar<T> for various values of T. Probably you're seeing a compiler error connected to the definition of operator+, though it's likely hidden behind a thicket of other templated-type errors.
I don't have a c++ compiler in front of me, but I believe template<class T> Bar<T> operator+(Bar<T> const & L, Bar<T> const & R) will behave as you expect.
Related
So I was trying to write a default function version when there are no template arguments passed in the following code:
struct A{ int x; };
struct B : public A { int y;};
struct C {
void set(const A& v) { v_ = v; }
template <typename T>
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
template <>
const A& get() { return v_;}
A v_;
};
int main() {
B b;
C c;
c.set(b);
(void)c.get<B>().y;
(void)c.get<A>().x;
//(void)c.get().x; << Error
}
But it doesn't work at the indicated Error line above with this error:
test.cpp:22:13: error: no matching member function for call to 'get'
(void)c.get().x;
~~^~~
test.cpp:9:14: note: candidate template ignored: couldn't infer template argument 'T'
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
^
1 error generated.
I do understand the issue that since no template argument was passed in the client call, it was unable to infer the typename but is there a way to provide a default implementation like the one in the above code when that happens? Essentially I want to avoid writing client code as (void)c.get<A>().x; and instead, adopt the default route implicitly.
As an alternative solution, you can specify A as default template argument for parameter T, e.g.
struct C {
void set(const A& v) { v_ = v; }
template <typename T = A>
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
template <>
const A& get() { return v_;}
A v_;
};
int main() {
B b;
C c;
c.set(b);
(void)c.get<B>().y; // call the primary template
(void)c.get<A>().x; // call the specification
(void)c.get().x; // call the specification
}
You can delete the template <> part.
struct C {
void set(const A& v) { v_ = v; }
template <typename T>
const T& get() { return reinterpret_cast<T&>(const_cast<A&>(v_)); }
const A& get() { return v_;}
A v_;
};
Is it possible to make this code work as I'd like? I.e. to allow the concept to have access to a private member funcion?
template <typename T>
concept bool Writeable()
{ return requires (T x,std::ostream os) { { x.Write(os) } -> void }; }
template <Writeable T>
void Write(std::ostream &os,const T &x) { x.Write(os); }
class TT
{
private:
void Write(std::ostream &os) const { os << "foo"; }
//friend concept bool Writeable<TT>();
friend void ::Write<TT>(std::ostream &,const TT &);
};
Thanks
No. Concepts explicitly are not allowed to be friends.
n4377 7.1.7/2
Every concept definition is implicitly defined to be a constexpr
declaration (7.1.5). A concept definition shall not be declared with
the thread_local, inline, friend, or constexpr specifiers, nor shall a
concept definition have associated constraints (14.10.2).
We can reduce it to this example to show that the access really is the problem:
template <typename T>
concept bool Fooable = requires (T t) { { t.f() } -> void };
struct Foo
{
private:
void f() {}
};
int main()
{
static_assert(Fooable<Foo>, "Fails if private");
}
You can however use a level of indirection, something like this:
template <typename T>
void bar(T t) { t.f(); }
template <typename T>
concept bool FooableFriend = requires(T t) { { bar(t) } -> void };
struct Foo
{
private:
void f() {}
template<typename T>
friend void bar(T t);
};
int main()
{
static_assert(FooableFriend<Foo>, "");
}
Live demo incorporating your example
Which works. Concepts are pretty early, so I imagine down the line that they might lift the friend restriction just as proposals have lifted restrictions for C++11/14 features in the past.
I have some trouble getting this to work. Here is a MVCE of my problem that passes the compilation phase
template<typename T>
struct foo
{
using type = T;
friend type bar(foo const& x) { return x.X; }
foo(type x) : X(x) {}
private:
type X;
};
template<typename> struct fun;
template<typename T> fun<T> bar(foo<T> const&, T); // forward declaration
template<typename T>
struct fun
{
using type = T;
friend fun bar(foo<type> const& x, type y)
{ return {bar(x)+y}; }
private:
fun(type x) : X(x) {}
type X;
};
int main()
{
foo<int> x{42};
fun<int> y = bar(x,7); // called here
};
The forward declaration is required for the compiler to resolve the call in main() (see this answer for the reason). However, the compiler now complains in the linking/loading phase:
Undefined symbols for architecture x86_64: "fun
bar(foo const&, int)", referenced from:
_main in foo-00bf19.o ld: symbol(s) not found for architecture x86_64
even though the function is defined in the friend declaration. If instead, I move the definition outside of that of struct func<>, i.e.
template<typename T>
struct fun
{
using type = T;
friend fun bar(foo<type> const& x, type y);
private:
fun(type x) : X(x) {}
type X;
};
template<typename T>
inline fun<T> bar(foo<T> const& x, T y)
{ return {bar(x)+y}; }
compilation fails with
foo.cc:29:10: error: calling a private constructor of class 'fun<int>'
{ return {bar(x)+y}; }
So, how can I get this to work? (compiler: Apple LLVM version 9.0.0 (clang-900.0.39.2), c++11)
Friend declaration inside of fun must match function template forward declaration, otherwise it will spawn an unrelated function:
template<typename TT> fun<TT> friend ::bar(foo<TT> const &, TT);
While definition should be placed outside:
template<typename T> fun<T> bar(foo<T> const& x, T y)
{ return {bar(x)+y}; }
online compiler
The shorter code to demonstrate the problem would be:
void foo(void);
template<typename T>
struct bar
{
friend void foo(void) {}
};
int main()
{
foo(); // undefined reference to `foo()'
return 0;
}
In-class function definition will never be used:
17.8.1 Implicit instantiation [temp.inst]
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and friends;
There are some quirky rules around friend functions.
namespace X {
template<class T>
struct A{
friend void foo(A<T>) {}
};
}
foo above is not a template function. It is a non-template friend function which exists in the namespace enclosing A but it can only be found via ADL lookup; it cannot be directly named as X::foo.
Much like members of templates can be templates themselves, or not, this is a non-template friend function that is created for each template class instantiation of A.
namespace X{
template<class T>
void foo(A<T>);
}
this foo is a function template named foo in namespace X. It is not the same as the non-template friend function foo above.
From this, most of your errors are clear. What you thought was a forward declaration was an unrelated template function. What you thought was a friend, was not, so you didn't have access to the private constructor.
We can fix this a few ways. My favorite way is to add a tag type.
template<class T>struct tag_t{using type=T;};
template<class T>
constexpr tag_t<T> tag{};
now we can use tag to ADL dispatch:
template<typename T>
struct fun {
using type = T;
friend fun bar(tag_t<fun>, foo<type> const& x, type y)
{ return {bar(x)+y}; }
private:
fun(type x) : X(x) {}
type X;
};
and then in main this works:
foo<int> x{42};
fun<int> y = bar(tag<fun<int>>, x, 7); // called here
But you might not want to mention tag<fun<int>>, so we just create a non-friend bar that does the call for us:
template<class T>
fun<T> bar(foo<T> const& x, type y)
{ return bar( tag<T>, x, y ); }
and now ADL does its magic and the proper non-template bar is found.
The other approach involves making the template function bar be a friend of fun.
Okay, I found an answer:
In order for the friend declaration to work properly, it must be qualified as a function template, i.e.
template<typename T>
struct fun
{
using type = T;
friend fun bar<T>(foo<type> const& x, type y);
// ^^^
private:
fun(type x) : X(x) {}
type X;
};
template<typename T>
inline fun<T> bar(foo<T> const& x, T y)
{ return {bar(x)+y}; }
However, combining the definition with the friend declaration still fails:
template<typename T>
struct fun
{
using type = T;
friend fun bar<T>(foo<type> const& x, type y)
{ return {bar(x)+y}; }
private:
fun(type x) : X(x) {}
type X;
};
results in:
foo.cc:20:16: warning: inline function 'bar<int>' is not defined [-Wundefined-inline]
friend fun bar<T>(foo<T> const& x, T y)
^
1 warning generated.
Undefined symbols for architecture x86_64:
"fun<int> bar<int>(foo<int> const&, int)", referenced from:
_main in foo-c4f1dd.o
ld: symbol(s) not found for architecture x86_64
which I don't really understand as the forward declaration is still in place.
This one compiles for me:
template<typename T>
struct foo
{
using type = T;
friend type bar(foo const& x) { return x.X; }
foo(type x) : X(x) {}
private:
type X;
};
template<typename> struct fun;
template<typename T> fun<T> bar(foo<T> const&, T); // forward declaration
template<typename T>
struct fun
{
using type = T;
friend fun bar<type>(foo<type> const& x, type y);
private:
fun(type x) : X(x) {}
type X;
};
template<typename T>
inline fun<T> bar(foo<T> const& x, T y)
{ return {bar(x)+y}; }
int main()
{
foo<int> x{42};
fun<int> y = bar(x,7); // called here
};
Using GCC 8.2.1. What I added is the template designation to the friend declaration.
Is it possible to make this code work as I'd like? I.e. to allow the concept to have access to a private member funcion?
template <typename T>
concept bool Writeable()
{ return requires (T x,std::ostream os) { { x.Write(os) } -> void }; }
template <Writeable T>
void Write(std::ostream &os,const T &x) { x.Write(os); }
class TT
{
private:
void Write(std::ostream &os) const { os << "foo"; }
//friend concept bool Writeable<TT>();
friend void ::Write<TT>(std::ostream &,const TT &);
};
Thanks
No. Concepts explicitly are not allowed to be friends.
n4377 7.1.7/2
Every concept definition is implicitly defined to be a constexpr
declaration (7.1.5). A concept definition shall not be declared with
the thread_local, inline, friend, or constexpr specifiers, nor shall a
concept definition have associated constraints (14.10.2).
We can reduce it to this example to show that the access really is the problem:
template <typename T>
concept bool Fooable = requires (T t) { { t.f() } -> void };
struct Foo
{
private:
void f() {}
};
int main()
{
static_assert(Fooable<Foo>, "Fails if private");
}
You can however use a level of indirection, something like this:
template <typename T>
void bar(T t) { t.f(); }
template <typename T>
concept bool FooableFriend = requires(T t) { { bar(t) } -> void };
struct Foo
{
private:
void f() {}
template<typename T>
friend void bar(T t);
};
int main()
{
static_assert(FooableFriend<Foo>, "");
}
Live demo incorporating your example
Which works. Concepts are pretty early, so I imagine down the line that they might lift the friend restriction just as proposals have lifted restrictions for C++11/14 features in the past.
Suppose there is the following definition in a header
namespace someNamespace {
template<class T, class S>
int operator + (const T & t, const S & s) {
return specialAdd (t, s);
}
}
Now I would like the user of the header to be able to do something like
using someNamespace::operator + <OneClass,SecondClass>;
which is obviously not possible.
The reason for this is that I do not want my operator + interfere with the standard operator + and therefore give the user the possibility to specify for which types operator + should be defined. Is there a way to achieve this?
Use the barton-nackman trick: http://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick
template<typename T,typename S>
class AddEnabled{
friend int operator + (T const& t, const S & s) {
T temp(t);
return temp.add(s);
}
};
class MyClass: public AddEnabled<MyClass,int>{
public:
MyClass(int val):mVal(val){
}
int add(int s){
mVal+=s;
return mVal;
}
private:
int mVal;
};
Here another example to overload the << operator:
template<typename T>
class OutEnabled {
public:
friend std::ostream& operator<<(std::ostream& out, T const& val) {
return static_cast<OutEnabled<T> const&>(val).ioprint(out);
}
protected:
template<typename U>
U& ioprint(U& out) const {
return static_cast<T const*>(this)->print(out);
}
};
To use it you can either let your class inherit from OutEnabled:
class MyClass: public OutEnabled<MyClass>{ ...
or you can define a sentry object e.g. in an anonymous namespace in a cpp file
namespace{
OutEnabled<MyClass> sentry;
}
As soon as the template OutEnabled gets instantiated (OutEnabled<MyClass>) the GLOBAL operator std::ostream& operator<<(std::ostream& out, MyClass const& val)
exists.
Further MyClass must contain a function (template) matching
template<typename U>
U& print(U& out) const {
out << mBottomLeft << "\t"<< mW << "\t"<< mH;
return out;
}
Since this is called by ioprint.
The function U& ioprint(U& out) is not absolutely necessary but it gives you a better error message if you do not have defined print in MyClass.
A type traits class that they can specialize, and enable_if in the operator+? Put the operator+ in the global namespace, but it returns
std::enable_if< for::bar<c1>::value && for::bar<c2>::value, int >
Where bar is a template type traits class in namespace for like this:
template<class T>
struct bar: std::false_type {};
I think that should cause sfinae to make your template plus only match stuff you specialize bar to accept.
You might want to throw some deconst and ref stripping into that enable_if, and do some perfect forwarding in your operator+ as well.