I'm looking for an "is_comparable" typetrait but can't find any.
It's very easy to build one that checks if an operator== for a class was implemented, but this excludes global defined operators.
Is it impossible to implement a is_comparable typetait?
I take it you mean a trait that, for two types L and R and
objects lhs and rhs of those types respectively, will yield true if
the lhs == rhs will compile and false otherwise. You appreciate that
in theory lhs == rhs might compile even though rhs == lhs, or lhs != rhs,
does not.
In that case you might implement the trait like:
#include <type_traits>
template<class ...> using void_t = void;
template<typename L, typename R, class = void>
struct is_comparable : std::false_type {};
template<typename L, typename R>
using comparability = decltype(std::declval<L>() == std::declval<R>());
template<typename L, typename R>
struct is_comparable<L,R,void_t<comparability<L,R>>> : std::true_type{};
This applies a popular SFINAE pattern for defining traits that is explained
in the answer to this question
Some illustrations:
struct noncomparable{};
struct comparable_right
{
bool operator==(comparable_right const & other) const {
return true;
}
};
struct any_comparable_right
{
template<typename T>
bool operator==(T && other) const {
return false;
}
};
bool operator==(noncomparable const & lhs, int i) {
return true;
}
#include <string>
static_assert(is_comparable<comparable_right,comparable_right>::value,"");
static_assert(!is_comparable<noncomparable,noncomparable>::value,"");
static_assert(!is_comparable<noncomparable,any_comparable_right>::value,"");
static_assert(is_comparable<any_comparable_right,noncomparable>::value,"");
static_assert(is_comparable<noncomparable,int>::value,"");
static_assert(!is_comparable<int,noncomparable>::value,"");
static_assert(is_comparable<char *,std::string>::value,"");
static_assert(!is_comparable<char const *,char>::value,"");
static_assert(is_comparable<double,char>::value,"");
If you want the trait to require that equality is symmetric and that inequality
also exists and is symmetric you can see how to elaborate it yourself.
Related
Sergiu Dotenco kindly contributed his implementation based on boost, could someone recommend an open-source c++11 style implementation, without boost? Google does provided some results, but this is a bit deep in math, I could not differentiate the quality of the implmentation.
Here's how c++11 has made compile time programming (slightly) easier
template <typename UIntType> constexpr bool IsPowerOfTwo(UIntType r)
{
return (r & (r - 1)) == 0;
}
namespace detail
{
template<class UIntType, UIntType r, bool>
struct ModuloHelper;
template<class UIntType, UIntType r>
struct ModuloHelper<UIntType, r, true>
{
template<class T>
static T calc(T value)
{
return value & (r - 1);
}
};
template<class UIntType, UIntType r>
struct ModuloHelper<UIntType, r, false>
{
template<class T>
static T calc(T value)
{
while (value >= r)
{ value -= r; }
return value;
}
};
}
template<class UIntType, UIntType r>
struct Modulo : detail::ModuloHelper<UIntType, r, IsPowerOfTwo(r)>
How to static_assert 3 items to be same at compile time like this.
union
{
std::uint32_t multibyte;
std::uint8_t bytes[4];
} test;
static_assert(sizeof(test) == sizeof(test.multibyte) == sizeof(test.bytes), "Union size mismatch.");
So of course the static_assert here fails because the last check will be 1 == 4. Is there more clean way besides
static_assert(sizeof(test.bytes) == sizeof(test.multibyte) && sizeof(test) == sizeof(test.bytes), "Union size mismatch.");
You could write a struct for that:
template<typename...> struct AllSame;
template<typename Arg1, typename Arg2, typename... Args>
struct AllSame<Arg1, Arg2, Args...>
{
static constexpr bool value = sizeof(Arg1) == sizeof(Arg2) && AllSame<Arg1, Args...>::value;
};
template<typename Arg>
struct AllSame<Arg>
{
static constexpr bool value = true;
};
Not tested, might contain errors.
If you are able to use c++14 then by the following example you can static_assert instances too, if they can be used in a constant expression:
template<typename T, typename... Ts>
constexpr bool compare_sizes(T&&, Ts&&...) noexcept {
using expand = int[];
bool result = sizeof...(Ts) > 0;
static_cast<void>(expand {
0, (static_cast<void>(result &= (sizeof(Ts) == sizeof(T))), 0)...
});
return result;
}
Example of use with your union { /* ... */ } test:
static_assert(compare_sizes(test, test.multibyte, test.bytes), "Size mismatch.");
Note that variable declaration and use of static_cast statement are prohibited in a constexpr function body until c++14.
Is it possible to detect the container type from the iterator type?
For example,
#include<traits>
int main(){
static_assert(std::is_same<
container_of<std::vector<double>::iterator>::type, std::vector<double>>{});
static_assert(std::is_same<
container_of<std::list<int>::iterator>::type, std::list<int>>{});
}
(Of course some iterators type will not give a container (or not give a unique container), for example a raw pointer or a stream iterator, but in those cases it can soft-SFINAE-fail.)
The first attempt is
template<class T, template<class> class Cont> Cont<T> aux(typename Cont<T>::iterator it);
template<class Iterator> struct container_of{
using type = decltype(aux(Iterator{}));
};
However, it doesn't work because the compiler can't detect the type of T (it is not in a deductible context).
Motivation: I want to detect whether the associated container of an iterator has a .data() member.
Instead of your primitive being an iterator, make your primitive be a range.
template<class It, bool Contiguous, class D=void>
struct range_t {
using Self = std::conditional< !std::is_same<D, void>, D, range_t >;
It b, e;
It begin() const { return b; }
It end() const { return e; }
Self without_front( std::size_t i = 1 ) const {
return {std::next(begin(), i), end()};
}
Self without_back( std::size_t i = 1 ) const {
return {begin(), std::prev(end(), i)};
}
bool empty() const { return begin()==end(); }
std::size_t size() const { return std::distance( begin(), end() ); }
};
template<class It>
struct range_t<It, true, void>:
range_t<It, false, range_t<It, true>>
{
using Base = range_t<It, false, range_t<It, true>>;
range_t( It b, It e ):Base(b,e) {}
auto* data() const {
if (empty()) return nullptr;
return std::addressof(*this->begin()); }
}
};
Track (manually) what containers are contiguous:
template<class T, class=void>
struct is_contiguous_container : std::false_type{};
template<class T>
struct is_contiguous_container<T const, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T volatile, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T const volatile, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T, std::enable_if_t< has_data_ptr<T>{} >>:
std::true_type{};
template<class T, std::size_t N>
struct is_contiguous_container<T[N],void> : std::true_type{};
The contiguous containers are array, std::array and std::vector, so not much to track. range_t< ?, true, ? > is also contiguous. Just write has_data_ptr, that is true iff T.data() returns a pointer to non-void.
template<class C>
auto range( C&& c ) {
using std:begin; using std::end;
auto b = begin(c), e = end(c);
using It = decltype(b);
using R = range_t<It, is_contiguous_container<std::remove_reference_t<C>>{}>;
return R{ b, e };
}
range now smartly converts a container into a range_t, keeping track of if it is contiguous or not.
range_t supports r.without_front( r.size()/2 ) to divide and conquer.
When a range is contiguous, just call .data() on it. When it isn't, don't.
In your application if you just want to know whether the container has a .data() member, it might be enough for you to check if it is random access (using std::iterator_traits<Iter>::iterator_category()).
Otherwise, I think you might be able to use a combination of the technique in: How to check if two types come from the same templated class and partial specialization for every standard container type.
Or wait for c++17 which has a new contiguous iterator concept: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html
What I am doing at the moment is to manually register all (some really) of the iterators that are contiguous.
Since I will always need this in combination with some way to extract the raw pointer, I directly code a single function called data that returns the pointer.
The code is not funny, it considers std::vector<>::iterator, std::basric_string<>::iterator, for illustration (to show that it will always be incomplete) I also added boost::static_vector<>, raw pointer and anything convertible to a pointer. (boost::array<>::iterator and std::array<>::iterator and begin/end(std::valarray) are effectively included because the iterators are pointers).
I also had to include the const_iterator cases.
#include<type_traits>
#include<vector> // the code below needs to know about std::vector
#include<boost/container/static_vector.hpp> // ... and all possible contigous containers :(
template<
class ContiguousIterator, // well ProbablyContiguos
typename = std::enable_if_t<
/**/std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{}
or std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::const_iterator>{}
or std::is_same<ContiguousIterator, typename std::basic_string<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{}
or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::iterator>{}
or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::const_iterator>{}
// many many other possible iterators :(
or std::is_pointer<ContiguousIterator>{}
or std::is_constructible<typename std::iterator_traits<ContiguousIterator>::pointer, ContiguousIterator>{}
>
>
typename std::iterator_traits<ContiguousIterator>::pointer
data(ContiguousIterator const& it){return std::addressof(*it);}
int main(){
std::vector<double> v(30);
v[0] = 10.;
assert( *data(v.begin()) == 10. );
}
Feedback is welcomed.
I have the following scenario:
struct AP;
struct B
{
B() : m(2) {}
int m;
};
struct A : private B
{
A() : B(), n(1) {}
private:
int n;
friend AP;
};
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
struct A_B {
using type = typename std::enable_if< std::is_base_of< typename std::remove_reference<T>::type,
A >::value,
T >::type;
};
template<typename T>
operator typename A_B<T>::type()
{
return static_cast<T>(a_);
}
template<typename T>
typename A_B<T>::type get()
{
return static_cast<T>(a_);
}
int& n() { return a_.n; }
private:
A& a_;
};
int main()
{
A a;
AP ap(a);
ap.n() = 7;
const B& b = ap.get<const B&>();
//const B& b = ap; candidate template ignored: couldn't infer template argument 'T'
//auto b = static_cast<const B&>(ap); candidate template ignored: couldn't infer template argument 'T'
std::cout<<b.m;
}
The commented lines wouldn't compile. Clang++ notes that "candidate template ignored: couldn't infer template argument 'T'"
Why am I not able to get a reference to A's base with the cast operator?
I think the code would look much nicer that way.
The answer that you posted works, but is overkill unless you really want a static_assert message.
Classic templating works just fine in this instance because A is already convertible to B:
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
operator T()
{
return a_;
}
template<typename T>
T get()
{
return a_;
}
int& n() { return a_.n; }
private:
A& a_;
};
Demo
I found the answer here: http://www.mersenneforum.org/showthread.php?t=18076
This is the key: "when you want the compiler to deduce argument types, those types must not be dependent types"
With this it compiles:
template<typename T>
operator T()
{
static_assert(std::is_base_of< typename std::remove_reference<T>::type,A >::value,
"You may cast AP only to A's base classes.");
return static_cast<T>(a_);
}
I am wondering if c++11/c++14 would/already support something like vector<auto>?
If not, Is there any reason?
It's not supported directly, and not immediately clear exactly what you want it to do.
Comments have already mentioned a couple of possibilities (such as Boost any and variant classes) for creating heterogeneous collections. I hope this isn't what you were after, because heterogeneous collections fit poorly with C++ so using them is ugly and clumsy. I suppose there are cases/situations where these really would be the best choices available, but at least in my experience, those cases are fairly rare.
Another possible interpretation of what you might want would be a vector that (like auto in general) holds exactly one type, but that type is deduced from the initializer, so if you initialized the vector from some ints, you'd get a vector<int>, and if you initialized it from some strings, you'd get a vector<string>, and so on. Although the language doesn't support that directly, it is pretty easy to simulate it to at least some degree. Template classes can't/don't ever deduce template parameters, but template functions do/can. Therefore, we can create a tiny function template to take some initializers, deduce their type, and return a vector of that type. For example:
template <class T>
std::vector<T> make_vector(std::initializer_list<T> init) {
return std::vector<T>(init);
}
This returns a vector<T> (with T deduced from the type of data in the initializer list), so you can do things like:
auto a = make_vector({ 1, 2, 3, 4 }); // a -> vector<int>
auto b = make_vector({ 1.0, 2.0, 3.0 }); // b -> vector<double>
auto c = make_vector({ "1"s, "2"s, "3"s }); // c -> vector<std::string>
That last one requires a user-defined literal operator that's new in C++14 (which many compilers don't yet support). The rest should be fine with C++11.
There has also been some discussion (and a proposal in N3602) of adding a capability (perhaps to C++17) where you'd be able to define something like the make_vector above, but as something like a templated constructor for the class. This would let you use argument deduction on the constructor to deduce the template parameter for the class as a whole, so you'd be able to do something like:
X x(1); // deduces as X<int>
X x(2.0) // deduces as X<double>
Warning though: this has been proposed but not accepted. It may (easily) never be accepted--and even if it is, it may be altered significantly before that happens.
No, not in C++11 or C++14, which are already finished and published.
But it's possible that vector<auto> and similar things like tuple<auto...> will be in C++17 as part of the Concepts work.
It follows quite naturally from the fact that std::vector<T> can be used in function templates and class template partial specializations where T is a template parameter, and also from the fact that polymorphic lambdas allow auto as a function parameter type (which is shorthand for a function template with deduced parameters).
The Concepts TS allows a "generic function" to be declared like:
auto func(auto arg);
Since you can have a function template like this:
template<typename T>
auto func(std::vector<T> v);
it makes sense to extend the generic function syntax to allow:
auto func(std::vector<auto> v);
and once you allow that in a function declaration, it should also be possible to allow it in variable declarations:
std::vector<auto> v = function_returning_vector_of_something();
The reason it isn't in C++11 is that auto was new, and it would have been too ambitious to try and make it do too much. In C++14 polymorphic lambdas were new, and again, expanding the uses of auto any further would have been ambitious.
For C++17 we have more experience with using auto in real code, and compiler writers are familiar with implementing it and know what is possible without too much effort.
A boost::any can store an instance of any type that can be copied, which is a lot of types.
In order to get the data out of your any, you have to know the exact type you stored in it.
Writing a simple any isn't hard:
#include <memory>
#include <utility>
struct any_internal {
virtual any_internal* clone() const = 0;
virtual ~any_internal() {};
};
template<class T>
struct any_details;
class any {
std::unique_ptr<any_internal> internal;
public:
any() = default;
any( any && ) = default;
any( any const&& o):any(o) {}
any( any & o ):any( const_cast<any const&>(o) ) {}
any& operator=( any && ) = default;
any& operator=( any const&& o ) { return this->operator=( o ); };
any& operator=( any & o ) { return this->operator=( const_cast<any const&>(o) ); };
any( any const& o ):internal( o.internal?o.internal->clone():nullptr ) {}
any& operator=( any const& o ) {
any tmp(o);
using std::swap;
swap( internal, tmp.internal );
return *this;
}
template<class U>
void reset( U&& o );
template<class U, class... Args>
void emplace( Args&&... args );
template<class U>
any( U&& o );
template<class U>
any& operator=(U&& o);
template<class T> T* get();
template<class T> T const* get() const;
template<class T> T* fast_get();
template<class T> T const* fast_get() const;
explicit operator bool() const { return internal!=nullptr; }
};
template<class T>
struct any_details : any_internal {
T t;
template<class...Args>
any_details( Args&&... args ):t(std::forward<Args>(args)...) {}
any_internal* clone() const override { return new any_details<T>{t}; }
};
template<class U, class... Args>
void any::emplace( Args&&... args ) {
internal.reset( new any_details<U>( std::forward<Args>(args)... ) );
}
template<class U>
void any::reset( U&& o ) {
emplace<typename std::decay<U>::type>( std::forward<U>(o) );
}
template<class U>
any::any( U&& o ) {
reset( std::forward<U>(o) );
}
template<class U>
any& any::operator=(U&& o) {
reset( std::forward<U>(o) );
return *this;
}
template<class T> T* any::get() {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::get() const {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T* any::fast_get() {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::fast_get() const {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
and a std::vector<any> behaves much like you might want a std::vector<auto> to do.
Increased efficiency can be achieved via small buffer optimizations (ie, store the T within the any if the t is small, instead of using the heap).
You'd probably also want to split get from fast_get, where get does a dynamic_cast and fast_get does a static_cast, again for efficiency. (When you know for certain, you can fast_get)
Basically this is a gussied up void*.