Ambiguous base class conversion with a compressed pair - c++

So I tried creating a compressed pair using the empty base optimization. I would like it such that if class a and b are empty then compressed_pair<a, b> is empty as well. So I defined my compressed pair something like this:
template <class First, class Second>
struct compressed_pair : First, Second
{
compressed_pair() {}
compressed_pair(const First& x, const Second & y)
: First(x), Second(y)
{}
First& first() { return *this; }
Second& second() { return *this; }
};
However, if one of the types inherit from the other it becomes ambiguous. For example, when I compile this program:
struct a
{};
struct b : a
{};
int main()
{
compressed_pair<a, b> p;
auto x = p.first();
}
I get this error from clang:
compressed_pair.cpp:8:30: error: ambiguous conversion from derived class 'compressed_pair<a, b>' to base class 'a':
struct compressed_pair<struct a, struct b> -> struct a
struct compressed_pair<struct a, struct b> -> struct b -> struct a
First& first() { return *this; }
^~~~~
compressed_pair.cpp:21:16: note: in instantiation of member function 'compressed_pair<a, b>::first' requested here
auto x = p.first();
^
So how can I avoid the ambiguous conversion and still have compressed_pair<a, b> be empty?

The problem that you have is that from compressed_pair there are two bases to which the conversion can apply. You need to be able to drive the compiler into selecting one of them. The first thing that comes to mind is to add another layer of inheritance that you can use as a selector:
template <int N, typename T>
struct element : T {};
template <typename T, typename U>
struct compressed_pair : element<0, T>, element<1, U> { ... };
Then your implementation for the accessors could be:
template <typename T, typename U>
T& compressed_pair<T,U>::first() {
return static_cast<element<0,T>&>(*this);
}
The cast inside the accessor forces the selection of one of the two direct bases, element<0,T>. From that point onwards, there is only one base of type T.
You can also use move the accessor to that intermediate step, rather than have it in the complete type. Finally, through specialization you should be able to provide a different implementation for element that supports non-class types as your current implementation will choke on types like int.

Use virtual inheritance to avoid ambiguity or require that First and Second do not derived from each other. It's an either/or decision. You need to decide whether avoiding ambiguity or allowing the empty base optimisation is more important to you.
Generally speaking, to avoid ambiguity, the one that is inherited more than once (i.e. by both your compressed_pair and the other struct type) needs to be a virtual base. Since the template might be instantiated using anything, this means that both First and Second must be a virtual base of compressed_pair, and a must be a virtual base of b.
If you always know that Second might be derived from First but First will never be derived from Second you can relax this somewhat (with the cost of ambiguity again, if First is derived from Second).
Bear in mind that virtual inheritance does impose some constraints on how the classes work. For example, it affects order of construction of bases, requires any subsequently derived classes to manage construction of virtual bases inherited via base classes, etc.

Related

How to pass a templated function parameter with a subclass of the templated type in C++?

Compiling the following contrived example:
class Base
{};
class Derived : public Base
{};
template< typename T >
class A
{};
class B
{
public:
static void f( const A< Base >& ) {}
};
int main()
{
A< Base > tb;
A< Derived > td;
B::f( tb );
B::f( td );
return 0;
}
using g++-8 gives me the following error:
error: no matching function for call to 'B::f(A<Derived>&)'
B::f( td );
note: no known conversion for argument 1 from 'A<Derived>' to 'const A<Base>&'
Why?
Since Derived is-a Base and it doesn't override any of Base's stuff, why can't I give a Derived in the place of a Base in the templated function parameter?
It is true that Derived is derived from Base, but that doesn't mean that A<Derived> must therefore be derived from A<Base>. C++ templates don't work this way.
All that A<Derived> is, is a class, instantiated by the A template. You could've simply declared:
class A_Derived {
// ...
};
With the same members (if it had any), and pretty much got the same results. Same for A<Base>. With nothing else in the picture, the two classes have absolutely nothing to do with each other, whatsoever. You can draw a mental picture here, as if you made the following declarations:
class A_Derived {
};
and
class A_Base {
};
Which is pretty much what this is history. Do you see A_Derived being explicitly derived from A_Base here? Obviously not. If something expects a reference or a pointer to A_Base, you cannot give it A_Derived, because the two classes have absolutely nothing to do with each other. They are independent classes.
P.S. You could declare an explicit specialization of A<Derived> as being derived from A<Base>, if you so wish, but specialization is a completely different topic...
Template instances, like A<Base> and A<Derived>, are different types. In particular they do not have any inheritance relationship even if Base and Derived do.
There are quite a few ways you can make what you want work.
First, you could make A<Derived> explicitly derive from A<Base>, but that means adding a whole class definition.
template<>
class A<Derived> : public A<Base>
{};
Second, you can provide an implicit conversion from A<Derived> to A<Base> in the form of a constructor template. You can use std::enable_if and std::is_base_of to only allow A<T> where T is derived from Base, or directly std::is_same if you only want to consider this particular Derived type.
template<typename T>
class A
{
template<typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
A(A<U> const& other);
};
Third, you can provide an implicit conversion in the form of an operator template, in much the same way.
template<typename T>
class A
{
template<typename U, typename = std::enable_if_t<std::is_base_of_v<U, T>>>
operator U();
};
Fourth, you can make f a function template and restrict what types it takes.
template<typename T, typename = std::enable_if_t<std::is_base_of_v<Base, T>>>
static void f(A<T> const& a);

Check if pointer to base class is one of derived with variadic templates

I have a polymorphic type Base which is the base-class of many other types:
class Base
{
Base() {}
virtual ~Base() {}
};
One of the derived class contains a value, that is templated by type T.
This class can also contain a pointer to another instance of that class, _stub, which may be of another type T, to act as a replacement of the value.
The restriction is that the other type must be one of the supported types indicated by the variadic templates.
So _stub is either of type T or of one of SupportedTypes.
What I would like the getValue function below to do is to return _v of type T if _stub is NULL, otherwise dynamic_cast _stub to its original derived type (let's say X), and cast it away to T.
The requirement is that the type X must have a cast operator to T.
The _stub is guaranteed to be either T or one of SupportedTypes.
template <typename T, typename... SupportedTypes>
class Generic : public Base
{
public:
Generic(): _v() {}
virtual ~Generic() {}
virtual T getValue() {
if (_stub) {
// Attempt dynamic_cast on _stub to type T or
// any of SupportedTypes until we find its original type X
// I'm looking for a solution that would look like the following line
X* p = dynamic_cast<T,SupportedTypes...>(_stub.get());
assert(p);
return (T)*p->_v;
}
return _v;
}
private:
T _v;
std::shared_ptr<Base> _stub;
};
Originally, I had no SupportedTypes parameter pack, and I would specialize getValue() for the type T and do a chain of dynamic_cast, but this was dependent on each type T and every function similar to getValue() would need this cascaded if/else dynamic_cast soup.
I was trying to experiment with the variadic templates SupportedTypes so that I could come up with a nicer solution where the derived class would only have to indicate the types _stub might be in a single place.
Does anyone have a clean solution to this problem ?
Solution:
I actually went with boost::variant thanks to the hint of #apple apple
The fact that this is happening inside a related class Generic and has the possibility of using another value if the pointer is null is irrelevant. What you want is a function template that converts to a single type derived from Base via dynamic_cast to one of a set of other types similarly derived:
class B;
// The real work:
template<class T>
T convert(B *b) {return static_cast<T&>(*b);}
template<class T,class U,class... Rest>
T convert(B *b) {
if(U *u=dynamic_cast<U*>(b)) return *u; // converted to T
return convert<T,Rest...>(b);
}
// Example hierarchy:
struct B {virtual ~B() {}};
struct X : B {};
struct Y : B {};
struct S : B { // convertible from other types
S() {}
S(X) {}
S(Y) {}
};
// Example usage:
S getS(B *b) {return convert<S,X,Y>(b);}

Check if member is declared in class

Is it possible to check if a member variable, a member function, or a type definition is declared in a given class?
Various questions on StackOverflow talk about checking if a given class merely contains a member, essentially using std::is_detected. But all these solutions detect the member also in derived classes, which may not declare the member themselves.
For example, the following doesn't compile.
#include <experimental/type_traits>
struct base
{
using type = std::true_type;
};
struct derived : public base { };
template<typename T>
using has_type_t = typename T::type;
template<typename T>
constexpr inline bool has_type_v =
std::experimental::is_detected<has_type_t, T>::value;
int main ()
{
static_assert (has_type_v<base>);
static_assert (!has_type_v<derived>);
}
Can any changes be made so that the two assertions hold? Or is reflection needed for that?
I don't see a way for type or static member, but for regular member, you can have distinguish base::m from derived::m:
template<typename T>
using has_m_t = decltype(&T::m);
template<typename T>
constexpr inline bool has_m_v =
std::experimental::is_detected_exact<int (T::*), has_m_t, T>::value;
And the test:
struct base { int m; };
struct derived : public base {};
struct without {};
static_assert( has_m_v<base>);
static_assert(!has_m_v<derived>);
static_assert(!has_m_v<without>);
Demo
I'm inclined to say no. Proving that is of course hard, but I can explain why I think so.
C++ is a compiled language. The compiler has an internal representation of types, which you can't access directly. The only way to access this internal representation is through the facilities of the language. Actual implementations can vary in the way they represent types internally, and often do have additional information to produce better error messages. But this is not exposed.
So yes, most compilers can enumerate base types, and know exactly where each member of a class came from. That's essential for good error messages. But you can't enumerate base classes at compile time, using only C++ templates.
You might think that for data members you could try tricks with addresses and offsets. That won't work, again because you need to know the size of all base classes - and you can't enumerate those.
You might also consider tricks in which you create further-derived helper classes. That's possible, but they suffer from the same problem. You can only derive from the given type, not from its parent(s). It's thus possible to create a child class, but not a sibling. And that child inherits from parent and grandparent alike. Even if you wrote using derived::type in the helper class, that would find base::type.
You can but with a limitation, your compiler must have an intrinsic that provides the list of base classes (GCC provides it).
If you can have access to such en intrinsic, the only difficulty is to check that member access through the derived is not actualy an access to a member of the base.
To check this, the idea is to use the 'ambiguous' access that happens when accessing a member declared in multiple bases of a derived class:
struct base
{
using type = std::true_type;
};
struct Derived1 : base{
};
struct Derived2 : base{
using type = std::true_type;
};
struct Test1: Derived1,base{};
struct Test2: Derived2,base{};
void g(){
Test1::type a;
Test2::type b;//Do not compile: 'type' is ambiguous
}
So you can generalize this trick this way:
template<class T,class Base>
struct MultiDer: T,Base{};
template<class T,class Base,class=void>
struct has_ambiguous_type
:std::true_type{};
template<class T,class Base>
struct has_ambiguous_type
<T,Base,std::void_t<typename MultiDer<T,Base>::type>>
:std::false_type{};
template<class T,class=void>
struct has_type
:std::false_type{};
template<class T>
struct has_type
<T,std::void_t<typename T::type>>
:std::true_type{};
template<class T,class...Bases>
constexpr inline auto has_type_declared_imp =
has_type<T>::value
//if any ambiguous access happens then T has 'type'
&& ( (has_ambiguous_type<T,Bases>::value || ...)
//or no ambiguity happened because none of the base has 'type'
|| (!has_type<Bases>::value && ...));
template<class T>
constexpr inline auto has_type_declared =
has_type_declared_imp<T,__direct_bases(T)...>;//GCC instrinsic
static_assert(has_type_declared<Derived2>);
static_assert(!has_type_declared<Derived1>);
The only problem is portability: your compiler must provides a mechanism to get access to the list of direct bases of a type. Here I have used the GCC's intrinsic __direct_bases.

How to implement std::tuple efficiently such that a tuple of empty types is itself an empty type?

I am implementing std::tuple and I want it to be as efficient in both object size and compile time as possible. I am following the suggestions given here and here.
To improve compile-time performance, the implementation does not use recursive inheritance and instead uses multiple inheritance with the tuple_leaf trick. Additionally it uses the empty base class optimization when possible to reduce the size of the type.
To ensure that the empty base class optimization is always applied, my implementation of tuple itself derives from a base class instead of storing the implementation inside a member variable. However, this causes problems with nested tuples because the tuple_leaf technique works through conversion to a base class. Nested tuples cause ambiguity because the same type of tuple_leaf may occur more than once in the derivation chain.
A program illustrating a simplification of the problem is posted below. Is there a simple way to disambiguate the conversion and allow the program to compile and execute without throwing the assert? I have considered detecting the nested tuple case and encoding the multidimensional position of each tuple_leaf within its type somehow, but that seems complex and would probably degrade compile-time performance.
#include <type_traits>
#include <cassert>
template<int i, class T, bool = std::is_empty<T>::value>
struct tuple_leaf
{
tuple_leaf(T x) : val(x) {}
T& get() { return val; }
T val;
};
template<int i, class T>
struct tuple_leaf<i,T,true> : private T
{
tuple_leaf(T x) : T(x) {}
T& get() { return *this; }
};
template<int i, class T1, class T2>
struct type_at
{
using type = T1;
};
template<class T1, class T2>
struct type_at<1,T1,T2>
{
using type = T2;
};
template<class T1, class T2>
struct tuple_base : tuple_leaf<0,T1>, tuple_leaf<1,T2>
{
tuple_base(T1 a, T2 b) : tuple_leaf<0,T1>(a), tuple_leaf<1,T2>(b) {}
template<int i>
tuple_leaf<i,typename type_at<i,T1,T2>::type> get_leaf()
{
// XXX how to disambiguate this conversion?
return *this;
}
};
// XXX deriving from tuple_base rather than
// making tuple_base a member is the root of the issue
template<class T1, class T2>
struct my_tuple : tuple_base<T1,T2>
{
my_tuple(T1 a, T2 b) : tuple_base<T1,T2>(a, b) {}
};
template<int i, class T1, class T2>
typename type_at<i,T1,T2>::type& get(my_tuple<T1,T2>& t)
{
return (t.template get_leaf<i>()).get();
}
template<class T1,class T2>
my_tuple<T1,T2> make_tuple(T1 a, T2 b)
{
return my_tuple<T1,T2>(a,b);
}
struct empty {};
int main()
{
auto tuple = make_tuple(empty(), make_tuple(empty(),empty()));
assert((std::is_empty<decltype(tuple)>::value));
assert(sizeof(tuple) == sizeof(empty));
get<0>(tuple);
return 0;
}
The compiler output:
$ clang-3.5 -std=c++11 repro.cpp
repro.cpp:47:12: error: ambiguous conversion from derived class 'tuple_base<empty, my_tuple<empty, empty> >' to base class 'tuple_leaf<0, empty, true>':
struct tuple_base<struct empty, struct my_tuple<struct empty, struct empty> > -> tuple_leaf<0, struct empty>
struct tuple_base<struct empty, struct my_tuple<struct empty, struct empty> > -> tuple_leaf<1, struct my_tuple<struct empty, struct empty> > -> struct my_tuple<struct empty, struct empty> -> tuple_base<struct empty, struct empty> -> tuple_leaf<0, struct empty>
return *this;
^~~~~
repro.cpp:63:22: note: in instantiation of function template specialization 'tuple_base<empty, my_tuple<empty, empty> >::get_leaf<0>' requested here
return (t.template get_leaf<i>()).get();
^
repro.cpp:80:3: note: in instantiation of function template specialization 'get<0, empty, my_tuple<empty, empty> >' requested here
get<0>(tuple);
^
1 error generated.
When all you have is a hammer, everything looks like "why not try CRTP". Because CRTP solves all problems with templates.
Extend tuple_leaf with a class D derived, and pass the type of tuple_base in. (Alternatively, write a template<class...>struct types{}; and pass that in -- all you need is an type that uniquely distinguishes two different tuples).
Modify the get_leaf to get the appropriate class, and now there is no ambiguity.
Problems:
First, without ICF, this makes a bunch of methods that would be identical now distinct.
Second, if you implement recursive tuples, this breaks horribly. The above relies on the fact that a tuple containing a subtuple X has a different set of types in it than the subtuple.
Third, when I tried it myself with the above code, I get empty structures with non-1 size. Strange. And if I bypass the static asserts and the like, get<0> segfaults. This could be an artifact of your simplified problem, I am uncertain.

Using decltype in a late specified return in CRTP base class

I'm trying to use decltype in the late specified return of a member function in a CRTP base class and it's erroring with: invalid use of incomplete type const struct AnyOp<main()::<lambda(int)> >.
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<const Op*>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
template<class Functor>
struct AnyOp : Operation<AnyOp<Functor> >
{
explicit AnyOp(Functor func) : func_(func) {}
template<class Foo>
bool call_with_foo(const Foo &foo) const
{
//do whatever
}
private:
Functor func_;
};
I'm basically trying to move all of the sfinae boiler plate into a base class so I don't need to repeat it for every Operation that I create (currently each operation has 6 different calls and there are ~50 operations so there is quite a lot of repetition with the enable_if's).
I've tried a solution which relied on overloading but one of the types which may be passed is anything that's callable(this can be a regular functor from C++03 or a C++0x lambda) which I bound to a std::function, unfortunately, the overhead from std::function, although very minimal, actually makes a difference in this application.
Is there a way to fix what I currently have or is there a better solution all together to solve this problem?
Thanks.
You are, as another answer describes already, trying to access a member of a class in one of the class' base class. That's going to fail because the member is yet undeclared at that point.
When it instantiates the base class, it instantiates all its member declarations, so it needs to know the return type. You can make the return type be dependent on Foo, which makes it delay the computation of the return type until Foo is known. This would change the base class like the following
// ignore<T, U> == identity<T>
template<typename T, typename Ignore>
struct ignore { typedef T type; };
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<typename ignore<const Op*, Foo>::type>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
This artificially makes the static_cast cast to a type dependent on Foo, so it does not immediately require a complete Op type. Rather, the type needs to be complete when operator() is instantiated with the respective template argument.
You are trying to refer to a member of a class from one of its own base classes, which will fail since the class's body doesn't exist within its base class. Can you pass the logic for computing the return type of call_with_foo as a metafunction to the base class? Is that logic ever going to be complicated?
Another option, depending on how much flexibility you have in changing your class hierarchy (and remember that you have template typedefs), is to have the wrapper inherit from the implementation class rather than the other way around. For example, you can write a AddParensWrapper<T> that inherits from T and has operator() that forwards to T::call_with_foo. That will fix the dependency problem.