Getting the number of dimensions of a std::vector/std::array - c++

Let's say I want a class/struct type, inheriting from integral_constant<size_t, N> where N is the dimension and the dimension is achieved as follows:
template<class T>
struct dimension;
template<class T>
struct dimension<vector<T>> : integral_constant<size_t, 1> {};
template<class T>
struct dimension<vector<vector<T>>> : integral_constant<size_t, 2> {};
And then
cout << dimension<vector<int>>::value; // 1
cout << dimension<vector<vector<int>>>::value; // 2
But obviously this is not perfect, as the number of dimensions can be a infinite (in theory). Is there a way to achieve a generic solution to this?
Suggestion: I went in this direction, but no further:
template<class T, class... Tn>
struct dimension<vector<Tn...>> : integral_constant<size_t, sizeof...(Tn)> {};
Since std::vector has other template parameters this wouldn't work.

A bit hard to define "what's a container". The below checks for value_type, iterator, and const_iterator nested typedefs. Tweak the void_t check as you want. (For instance, if you want only things that can be subscripted to be recognized as containers, then add decltype(std::declval<T&>()[0]) to the list.)
Note that dimension_impl's specialization calls dimension. this allows you to specialize dimension for container-like things you don't want to be treated as a container (std::string comes to mind).
template<class T> struct dimension;
namespace details {
template<class T, class = void>
struct dimension_impl {
static constexpr std::size_t value = 0;
};
template<class T>
struct dimension_impl<T, std::void_t<typename T::value_type,
typename T::iterator,
typename T::const_iterator>> {
static constexpr std::size_t value = 1 + dimension<typename T::value_type>::value;
};
}
template<class T>
struct dimension : std::integral_constant<std::size_t,
details::dimension_impl<T>::value> {};

You can do this for a std::vector (note that the template parameter list of a std::vector is longer than 1):
template<typename T>
struct dimension { static constexpr std::size_t value = 0; };
template<typename T, typename... V>
struct dimension<std::vector<T, V...>>{
static constexpr std::size_t value = 1 + dimension<T>::value;
};
This works instead for a std::array:
template<typename>
struct dimension { static constexpr std::size_t value = 0; };
template<typename T, std::size_t N>
struct dimension<std::array<T, N>>{
static constexpr std::size_t value = 1 + dimension<T>::value;
};
It follows a minimal, working example:
#include<vector>
#include<iostream>
template<typename T>
struct dimension { static constexpr std::size_t value = 0; };
template<typename T, typename... V>
struct dimension<std::vector<T, V...>>{
static constexpr std::size_t value = 1 + dimension<T>::value;
};
int main() {
std::cout << dimension<std::vector<std::vector<int>>>::value << std::endl;
}

Related

How to find maximum dereferenceable-level of the parameter T using template

I am designing a "dereferencer" class, for fun.
I wrote some structs and aliass :
template <class _T>
using deref_type = decltype(*std::declval<_T>());
template <class _T, class _SFINAE>
struct is_derefable : std::false_type {};
template <class _T>
struct is_derefable< _T, deref_type<_T> > : std::true_type
{
using return_type = deref_type<_T>;
};
template<class _T>
using check_derefable = is_derefable<T, deref_type<T>>;
and let's say that there is a variable with type T = std::vector<int**>::iterator, which is the iterator dereferenced into a level-2 pointer, thus has a 3-level dereferenceability.
Here, I want to know the maximum level of "dereferenceability" of an arbitrary type T, at the compile-time.
std::cout << deref_level<std::vector<int**>::iterator>::max << std::endl; // this should prints 3
I thought that it would be way similar to generating a sequence at the compile-time: Template tuple - calling a function on each element
, but I can't draw a concrete picture of it.
Here are what I've tried:
template<class _TF, class _T>
struct derefability {};
template<int _N, class _derefability>
struct deref_level;
template<int _N, class _T>
struct deref_level<_N, derefability<std::false_type, _T>>
{
static const int max = _N;
};
template<int _N, class _T>
struct deref_level<_N, derefability<std::true_type, _T>> :
deref_level<_N + 1, derefability<typename check_derefable<deref_type<_T>>::type, deref_type<_T>>>{};
deref_level<0, derefability<check_derefable<T>::type, T>::max;
but it does not work...(compiler says that max is not a member of tje class) What went wrong?
Here is a recursive implementation using SFINAE directly:
template <class T, class = void>
struct deref_level {
enum : std::size_t { value = 0 };
};
template <class T>
struct deref_level<T, decltype(void(*std::declval<T const &>()))> {
enum : std::size_t { value = deref_level<decltype(*std::declval<T const &>())>::value + 1 };
};
See it live on Wandbox
I don't know what went wrong with your template example, but here's an implementation using a recursive consteval function:
#include <type_traits>
template<typename T, int N = 0>
consteval int deref_level()
{
if constexpr (std::is_pointer<T>::value) {
typedef typename std::remove_pointer<T>::type U;
return deref_level<U, N + 1>();
} else {
return N;
}
}
int main() {
return deref_level<int****>(); // Returns 4
}
After a few days of work, I was able to write code that works without causing an error in MSVC13.
First of all, I needed a robust module to check the dereferenceability of the type.
Since the struct-level SFINAE check fails, I took another method that deduces the return type from overloaded functions with auto->decltype expression, based on the answer: link
template<class T>
struct is_dereferenceable
{
private:
template<class _type>
struct dereferenceable : std::true_type
{
using return_type = _type;
};
struct illegal_indirection : std::false_type
{
using return_type = void*;
};
template<class _type>
static auto dereference(int)->dereferenceable<
decltype(*std::declval<_type>())>;
template<class>
static auto dereference(bool)->illegal_indirection;
using dereferenced_result = decltype(dereference<T>(0));
public:
using return_type = typename dereferenced_result::return_type;
static const bool value = dereferenced_result::value;
};
Now I have a robust dereferenceability-checker, the remaining part becomes far easy.
template< class T,
class D = typename is_dereferenceable<T>::return_type >
struct dereferenceability;
template< class T >
struct dereferenceability<T, void*>
{
using level = std::integral_constant<int, 0>;
};
template< class T, class D >
struct dereferenceability<T, D&>
{
using level = std::integral_constant<int, dereferenceability<D>::level::value + 1>;
};
int main()
{
static_assert(dereferenceability<int>::level::value == 0, "something went wrong");
static_assert(dereferenceability<int****>::iterator>::level::value == 4, "something went wrong");
return 0;
}
I've tested codes above in Visual Studio 2013, and no error occured.

C++ partial template specialization issue

Given a matrix class
using index_t = int;
template<index_t M, index_t N, typename S>
struct mat {
// matrix implementation
};
I would like to have a generic way of obtaining the elementCount for a given type T that will work for both matrices and scalars. For example, I imagine being able to do this:
dimensionality<mat<1,2,double>>(); // returns 2
dimensionality<mat<2,2,float>>(); // returns 4
dimensionality<double>(); // returns 1
or perhaps something like this:
attributes<mat<1,2,double>>::dimensionality; // returns 2
attributes<mat<2,2,float>>::dimensionality; // returns 4
attributes<double>::dimensionality; // returns 1
My attempt:
I tried doing the following (thinking that I am partially specializing the struct attributes):
template<typename T>
struct attributes {};
template<typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>>
struct attributes<S> { // <--- compiler error on this line
static constexpr index_t dimensionality = 1;
};
template<index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>> {
static constexpr index_t dimensionality = M * N;
};
but I get a compiler error on the indicated line. Can you help me (either by suggesting a better approach, or to understand what I'm doing wrong)?
First, the specialization cannot have more template parameters than the primary template, but your code puts typename = std::enable_if_t for the arithmetic case.
Secondly, in order to make this std::enable_if_t to work, it would need to result in something that makes the specialization more specialized than the primary template, not only valid. For that, you could use the void_t trick:
template <typename T, typename = void>
struct attributes {};
template <typename S>
struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> {
static constexpr index_t dimensionality = 1;
};
This also entails that the specialization for matrices should include this void parameter as well:
template <index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>, void> {
static constexpr index_t dimensionality = M * N;
};
DEMO
Your trait could, however, be shortened to:
template <typename T>
struct attributes {
static_assert(std::is_arithmetic<T>::value, "T must be arithmetic or mat");
static constexpr index_t dimensionality = 1;
};
template <index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>> {
static constexpr index_t dimensionality = M * N;
};
DEMO 2
That is, just consider arithmetic types in the primary template, when no specialization matches.
You could add another template parameter with default type void, then specify the std::enable_if as the corresponding template argument in the partial specialization for arithmetic types. (And adjust the partial specialization for mat too.)
template<typename T, typename = void>
struct attributes {};
template<typename S>
struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> {
static constexpr index_t dimensionality = 1;
};
template<index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>, void> {
static constexpr index_t dimensionality = M * N;
};
LIVE
Wrapping a trait-based static constant: std::integral_constant
You may want to make use of std::integral_constant from <type_traits> to implement your trait,
[...] std::integral_constant wraps a static constant of specified type. It is the base class for the C++ type traits.
as well as supply a helper variable template dimensionality_v for ease of use:
#include <type_traits>
// Default dimensionality 0.
template <class T, typename = void>
struct dimensionality : std::integral_constant<index_t, 0> {};
template <typename S>
struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
: std::integral_constant<index_t, 1> {};
template <index_t M, index_t N, typename S>
struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
template <class T>
inline constexpr index_t dimensionality_v = dimensionality<T>::value;
DEMO.
Alternatively, if you don't want to allow a default dimensionality for types that are neither fulfilling std::is_arithmetic_v nor equals mat:
template <class T, typename = void>
struct dimensionality {};
template <typename S>
struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
: std::integral_constant<index_t, 1> {};
template <index_t M, index_t N, typename S>
struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
template <class T>
inline constexpr index_t dimensionality_v = dimensionality<T>::value;
DEMO.

getting a value for any type in a constexpr environment without default constructibility [duplicate]

Is there a utility in the standard library to get the index of a given type in std::variant? Or should I make one for myself? That is, I want to get the index of B in std::variant<A, B, C> and have that return 1.
There is std::variant_alternative for the opposite operation. Of course, there could be many same types on std::variant's list, so this operation is not a bijection, but it isn't a problem for me (I can have first occurrence of type on list, or unique types on std::variant list).
Update a few years later: My answer here may be a cool answer, but this is the correct one. That is how I would solve this problem today.
We could take advantage of the fact that index() almost already does the right thing.
We can't arbitrarily create instances of various types - we wouldn't know how to do it, and arbitrary types might not be literal types. But we can create instances of specific types that we know about:
template <typename> struct tag { }; // <== this one IS literal
template <typename T, typename V>
struct get_index;
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: std::integral_constant<size_t, std::variant<tag<Ts>...>(tag<T>()).index()>
{ };
That is, to find the index of B in variant<A, B, C> we construct a variant<tag<A>, tag<B>, tag<C>> with a tag<B> and find its index.
This only works with distinct types.
I found this answer for tuple and slightly modificated it:
template<typename VariantType, typename T, std::size_t index = 0>
constexpr std::size_t variant_index() {
static_assert(std::variant_size_v<VariantType> > index, "Type not found in variant");
if constexpr (index == std::variant_size_v<VariantType>) {
return index;
} else if constexpr (std::is_same_v<std::variant_alternative_t<index, VariantType>, T>) {
return index;
} else {
return variant_index<VariantType, T, index + 1>();
}
}
It works for me, but now I'm curious how to do it in old way without constexpr if, as a structure.
You can also do this with a fold expression:
template <typename T, typename... Ts>
constexpr size_t get_index(std::variant<Ts...> const&) {
size_t r = 0;
auto test = [&](bool b){
if (!b) ++r;
return b;
};
(test(std::is_same_v<T,Ts>) || ...);
return r;
}
The fold expression stops the first time we match a type, at which point we stop incrementing r. This works even with duplicate types. If a type is not found, the size is returned. This could be easily changed to not return in this case if that's preferable, since missing return in a constexpr function is ill-formed.
If you dont want to take an instance of variant, the argument here could instead be a tag<variant<Ts...>>.
With Boost.Mp11 this is a short, one-liner:
template<typename Variant, typename T>
constexpr size_t IndexInVariant = mp_find<Variant, T>::value;
Full example:
#include <variant>
#include <boost/mp11/algorithm.hpp>
using namespace boost::mp11;
template<typename Variant, typename T>
constexpr size_t IndexInVariant = mp_find<Variant, T>::value;
int main()
{
using V = std::variant<int,double, char, double>;
static_assert(IndexInVariant<V, int> == 0);
// for duplicates first idx is returned
static_assert(IndexInVariant<V, double> == 1);
static_assert(IndexInVariant<V, char> == 2);
// not found returns ".end()"/ or size of variant
static_assert(IndexInVariant<V, float> == 4);
// beware that const and volatile and ref are not stripped
static_assert(IndexInVariant<V, int&> == 4);
static_assert(IndexInVariant<V, const int> == 4);
static_assert(IndexInVariant<V, volatile int> == 4);
}
One fun way to do this is to take your variant<Ts...> and turn it into a custom class hierarchy that all implement a particular static member function with a different result that you can query.
In other words, given variant<A, B, C>, create a hierarchy that looks like:
struct base_A {
static integral_constant<int, 0> get(tag<A>);
};
struct base_B {
static integral_constant<int, 1> get(tag<B>);
};
struct base_C {
static integral_constant<int, 2> get(tag<C>);
};
struct getter : base_A, base_B, base_C {
using base_A::get, base_B::get, base_C::get;
};
And then, decltype(getter::get(tag<T>())) is the index (or doesn't compile). Hopefully that makes sense.
In real code, the above becomes:
template <typename T> struct tag { };
template <std::size_t I, typename T>
struct base {
static std::integral_constant<size_t, I> get(tag<T>);
};
template <typename S, typename... Ts>
struct getter_impl;
template <std::size_t... Is, typename... Ts>
struct getter_impl<std::index_sequence<Is...>, Ts...>
: base<Is, Ts>...
{
using base<Is, Ts>::get...;
};
template <typename... Ts>
struct getter : getter_impl<std::index_sequence_for<Ts...>, Ts...>
{ };
And once you establish a getter, actually using it is much more straightforward:
template <typename T, typename V>
struct get_index;
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: decltype(getter<Ts...>::get(tag<T>()))
{ };
That only works in the case where the types are distinct. If you need it to work with independent types, then the best you can do is probably a linear search?
template <typename T, typename>
struct get_index;
template <size_t I, typename... Ts>
struct get_index_impl
{ };
template <size_t I, typename T, typename... Ts>
struct get_index_impl<I, T, T, Ts...>
: std::integral_constant<size_t, I>
{ };
template <size_t I, typename T, typename U, typename... Ts>
struct get_index_impl<I, T, U, Ts...>
: get_index_impl<I+1, T, Ts...>
{ };
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: get_index_impl<0, T, Ts...>
{ };
My two cents solutions:
template <typename T, typename... Ts>
constexpr std::size_t variant_index_impl(std::variant<Ts...>**)
{
std::size_t i = 0; ((!std::is_same_v<T, Ts> && ++i) && ...); return i;
}
template <typename T, typename V>
constexpr std::size_t variant_index_v = variant_index_impl<T>(static_cast<V**>(nullptr));
template <typename T, typename V, std::size_t... Is>
constexpr std::size_t variant_index_impl(std::index_sequence<Is...>)
{
return ((std::is_same_v<T, std::variant_alternative_t<Is, V>> * Is) + ...);
}
template <typename T, typename V>
constexpr std::size_t variant_index_v = variant_index_impl<T, V>(std::make_index_sequence<std::variant_size_v<V>>{});
If you wish a hard error on lookups of not containing type or duplicate type - here are static asserts:
constexpr auto occurrences = (std::is_same_v<T, Ts> + ...);
static_assert(occurrences != 0, "The variant cannot have the type");
static_assert(occurrences <= 1, "The variant has duplicates of the type");
Another take on it:
#include <type_traits>
namespace detail {
struct count_index {
std::size_t value = 0;
bool found = false;
template <typename T, typename U>
constexpr count_index operator+(const std::is_same<T, U> &rhs)
{
if (found)
return *this;
return { value + !rhs, rhs};
}
};
}
template <typename Seq, typename T>
struct index_of;
template <template <typename...> typename Seq, typename... Ts, typename T>
struct index_of<Seq<Ts...>, T>: std::integral_constant<std::size_t, (detail::count_index{} + ... + std::is_same<T, Ts>{}).value> {
static_assert(index_of::value < sizeof...(Ts), "Sequence doesn't contain the type");
};
And then:
#include <variant>
struct A{};
struct B{};
struct C{};
using V = std::variant<A, B, C>;
static_assert(index_of<V, B>::value == 1);
Or:
static_assert(index_of<std::tuple<int, float, bool>, float>::value == 1);
See on godbolt: https://godbolt.org/z/7ob6veWGr

Improve compile-time error messages in templated classes

I have a templated class which is supposed to accepts some kind of containers (std::array and std::vector) of some kind of of objects (in this example string and doubles).
My goal is to provide some clear compilation error if the class is constructed from the wrong combination of objects.
The following code compiles in Visual Studio 17, version 15.9.0.
///Performing checks
namespace checks
{
template <typename T>
struct CorrectType {
enum { value = false };
};
template <>
struct CorrectType<std::string> {
enum { value = true };
};
template <>
struct CorrectType<double> {
enum { value = true };
};
template <typename T>
struct CorrectContainer {
enum { value = false };
};
template <typename T, typename A>
struct CorrectContainer<std::vector<T, A>> {
enum { value = CorrectType<T>::value };
};
template <typename T, std::size_t N>
struct CorrectContainer<std::array<T, N>> {
enum { value = CorrectType<T>::value };
};
template <class Container>
void constexpr check(){
static_assert(checks::CorrectContainer<Container>::value, "Wrong container: only vectors/arrays of doubles/strings are accepted");
}
}
template <typename Container>
class Wrapper
{
public:
explicit Wrapper(const Container &container) : container_(container), size_(container.size())
{
//type checking is performed
checks::check<Container>();
}
void display() const {
for (int i = 0; i < size_; i++)
std::cout << this->container_[i] << " ";
std::cout << std::endl;
}
private:
Container container_;
int size_ = 0;
};
int main()
{
//Ok
Wrapper array_wrapper(std::array<double, 5>{0.0,1.0,2.0,3.0,4.0});
array_wrapper.display();
//Ok
Wrapper string_wrapper(std::array<std::string, 3>{ "a","b","c" });
string_wrapper.display();
//Error - working as intended but not clear what went wrong
Wrapper<std::vector<int>> vector_wrapper({ 1,2,3});
vector_wrapper.display();
}
The code above works as intended, but the error is ambiguous: we are not able to understand if the container is wrong or the kind of object contained is. Moreover, if the templated object has not a size member function, it will fail too early.
As I understand your query, invalid type detection can probably be sketched out as
template<class> struct ValidType;
template<template<class...> class> struct ValidContainer: std::false_type {};
template<> struct ValidContainer<std::vector>: std::true_type {};
template<class> struct ValidType: std::false_type {};
template<class> struct ValidType<double>: std::true_type {};
template<class> struct ValidType<std::string>: std::true_type {};
template<class> struct ValidArgument {
static_assert(false, "Both container and element type are wrong");
};
template<template<class...> class Ctr, class T, class... Ts>
struct ValidArgument<Ctr<T, Ts...>> {
static_assert(ValidContainer<Ctr>::value || ValidType<T>::value
, "Both container and element type are wrong");
static_assert(ValidContainer<Ctr>::value, "Container type is wrong");
static_assert(ValidType<T>::value, "Element type is wrong");
};
template<class T, std::size_t n> struct ValidArgument<std::array<T, n>> {
static_assert(ValidType<T>::value, "Element type is wrong");
};
(Note this is not the real code, merely a demonstration of an idea.)
Arrays are still evil, in the sense that std::array has a non-type parameter, and thus you cannot have a single template that checks the container, the ultimate check is still for the kind 0-type, with container checking in generic case and std::array being treated separately.
Alternatively, ValidType can be slightly more compact:
template<class T> using ValidType = std::bool_constant<
std::is_same_v<T, double> || std::is_same_v<T, std::string>>;
Or
template<class T> using ValidType = std::disjunction<
std::is_same<T, double>, std::is_same<T, std::string>>;
Or a less-standard type matching class. For instance:
template<class T, class... Ts> inline constexpr bool is_one_of_v =
std::disjunction_v<std::is_same<T, Ts>...>;
template<class T> using ValidType =
std::bool_constant<is_one_of_v<T, double, std::string>>;
This way you're less likely to get rogue specializations later.
You might move your check inside class (and split your condition):
template <typename Container>
class Wrapper
{
static_assert(checks::CorrectContainer<Container>::value,
"only std::vector/std::array allowed");
static_assert(checks::CorrectType<typename Container::value_type>::value,
"only double and std::string");
public:
// ...
};
Demo

Template type defined array initialisation

I have an array I want to initialise as a constexpr based on template paramaters (I think this will require c++14, as I envisage the answer requiring initialiser lists as constexpr).
Lets say I have a template
template<T t>
where
T = int[1][2][3]
now, i can extract the array sizes recursively using type_traits std::extent
what I'd like to do ultimately is generate a constexpr member with the dimensions of T as elements of myarray
std::array<int,3> myarray = {1,2,3};
I've seen what looks like a nice way to initialise an array using a variadic template
ref: How to construct std::array object with initializer list?
The question is, how to generate either an initialiser list or variadic template with the dimensions of T given T?1
The following is a bit complicated but it should work (with C++11):
#include <array>
#include <type_traits>
template<std::size_t...> struct seq {};
template<typename,typename> struct cat;
template<std::size_t... Is, std::size_t... Js>
struct cat<seq<Is...>,seq<Js...>>
{
using type = seq<Is...,Js...>;
};
template<typename> struct extract_seq { using type = seq<>; };
template<typename T,std::size_t N>
struct extract_seq<T[N]>
{
using type = typename cat< seq<N>, typename extract_seq<T>::type >::type;
};
template<typename T> struct extract_type { using type = T; };
template<typename T,std::size_t N>
struct extract_type<T[N]>
: extract_type<T>
{};
template<typename,typename> struct to_array_helper;
template<typename T, std::size_t... Is>
struct to_array_helper<T,seq<Is...>>
{
constexpr static const std::array<T,sizeof...(Is)> value {{ Is... }};
};
template<typename T, std::size_t... Is>
constexpr const std::array<T,sizeof...(Is)>
to_array_helper<T,seq<Is...>>::value;
template<typename T>
struct to_array
: to_array_helper<typename extract_type<T>::type,
typename extract_seq<T>::type>
{};
int main()
{
auto arr = to_array< int[1][2][3] >::value;
}
Live example
I don't think you need any special future C++. This works fine in C++11:
#include <array>
#include <iostream>
#include <type_traits>
#include <prettyprint.hpp>
template <typename T>
struct Foo
{
std::array<std::size_t, std::rank<T>::value> a;
Foo() : Foo(X<std::rank<T>::value>(), Y<>(), Z<T>()) { }
private:
template <unsigned int K> struct X { };
template <unsigned int ...I> struct Y { };
template <typename> struct Z { };
template <typename U, unsigned int K, unsigned int ...I>
Foo(X<K>, Y<I...>, Z<U>)
: Foo(X<K - 1>(),
Y<I..., std::extent<U>::value>(),
Z<typename std::remove_extent<U>::type>())
{ }
template <typename U, unsigned int ...I>
Foo(X<0>, Y<I...>, Z<U>)
: a { I... }
{ }
};
int main()
{
Foo<char[4][9][1]> x;
std::cout << x.a << std::endl;
}
Outputs:
[4, 9, 1]