I have a struct that manages 'views' into an array of variable type. The purpose of this is to provide a unified state vector for ODE simulation while at the same time working on individual segments of this vector from several other classes in an organized fashion. If this triggers a design pattern in your mind, please let me know.
My issue is that the first implementation ContainerHolderFirst, using Cont::pointer does not compile for const arrays.
My next attempt with std::conditional, mixing in Cont::const_pointer still doesn't work.
Only the third attempt with std::conditional and modification of Cont::value_type compiles (and seems to work in my larger project).
My questions are the following:
It would be nice if ContainerHolderFirst would work. I'd wish that const-ness of the type would be propagated to the pointer. Why isn't it?
I understand even less why ContainerHolderSecond doesn't work. The explanation in https://stackoverflow.com/a/1647394/1707931 rather suggests that this is the way to go, no? It does actually work. My bad.
Are there issues with the third approach that I haven't uncovered yet? Is there a simpler way?
Full C++11 code follows:
Update1: Fixing ContainerHolderSecond. It does compile with correct initialization. Also added ContainerHolderBarry suggested by Barry using decltype and declval.
This leaves the question whether any of the approaches are preferred? Will they lead to performance differences? They should all compile to the same object, no?
#include <iostream>
#include <array>
template <typename Cont>
class ContainerHolderFirst {
Cont& data_;
const static size_t offset_ = 1;
typename Cont::pointer data_view;
public:
ContainerHolderFirst(Cont& data) : data_(data), data_view(&data[offset_]) {}
};
template <typename Cont>
class ContainerHolderSecond {
using Pointer = typename std::conditional<std::is_const<Cont>::value,
typename Cont::const_pointer,
typename Cont::pointer>::type;
Cont& data_;
const static size_t offset_ = 1;
Pointer data_view;
public:
ContainerHolderSecond(Cont& data) : data_(data), data_view(&data[offset_]) {}
};
template <typename Cont>
class ContainerHolderBarry {
using Pointer = decltype(&std::declval<Cont&>()[0]);
Cont& data_;
const static size_t offset_ = 1;
Pointer data_view;
public:
ContainerHolderBarry(Cont& data) : data_(data), data_view(&data[offset_]) {}
};
int main() {
using namespace std;
array<int, 2> my_array;
ContainerHolderFirst<array<int, 2>> holder(my_array); // works
const array<int, 2> const_array{5,7};
// ContainerHolderFirst<const array<int, 2>> const_holder(const_array);
/* error: invalid conversion from 'const value_type* {aka const int*}' to 'std::array<int, 2ull>::pointer {aka int*}' [-fpermissive] */
ContainerHolderSecond<array<int,2>> second_holder(my_array); // works!
ContainerHolderSecond<const array<int,2>> const_holder(const_array); //updated; works as well; awkward
ContainerHolderThird<array<int,2>> third_holder(my_array); // still works
ContainerHolderThird<const array<int,2>> third_const_holder(const_array); //finally compiles as well
ContainerHolderBarry<array<int,2>> barry_holder(my_array);
ContainerHolderBarry<const array<int,2>> barry_const_holder(const_array);
}
You're making this unnecessarily difficult on yourself. If you want the type of &cont[offset], just ask for the type of that expression. Use std::declval along with decltype:
template <typename Cont>
class ContainerHolder {
using Pointer = decltype(&std::declval<Cont&>()[0]);
...
};
The only problem with ContainerHolderSecond is that you're using it incorrectly:
ContainerHolderSecond<array<int,2>> const_holder(const_array);
// ^-- insert "const" here
As for ContainerHolderFirst, the reason that array<T, N>::pointer is the same type as (array<T, N> const)::pointer is that there is no automatic way to determine where the const qualification should be added to the nested type, and there is no language facility to describe this (that is, we don't have const-qualified typedefs or type aliases).
Related
I'm reviewing a lot of code where I need to ensure there are no static_cast (or any cast) calls on variables that could be out of range of the enum class that is being cast to. Ideally I'd be able to receive a warning or have some way to detect code that is casting from, for example, an int when the enum class in question has an underlying type of unsigned char.
enum class some_enum_class : unsigned char
{
SomeVal,
};
int BadVal = 1000;
auto EnumVar = static_cast<some_enum_class>(BadVal); //Trigger Warning!
Is there any way to accomplish this? (hopefully in MSVC?)
Doing your own casting function can help you, you can wrap the const_cast function using concepts and constraints of c++20 which specifies the requirements on template arguments.
And for example clang tidy recognize it and throw a warning before any compilation.
#include <iostream>
#include <type_traits>
template<typename T, typename NewType>
concept isConvertible = std::is_convertible<NewType, T>::value;
template<typename T, typename NewType>
static NewType constraint_static_cast(T t)requires isConvertible<NewType, T>{
return static_cast<NewType>(t);
}
int main(){
enum class SomeEnumClass : unsigned char
{
SomeValue,
};
int bad_value = 1000;
auto EnumVar = constraint_static_cast<int, SomeEnumClass>(bad_value); //Trigger Warning!
auto EnumVar = constraint_static_cast<int, bool>(bad_value); //Work because of the concept
}
I am trying to implement a kind of matrix wrapper that takes a container of a container as template parameter.
But I get an error when trying to construct a matrix_wrapper of a const reference. The code seems to work with a non reference, non pointer, not const parameter and I would like to use the same code for both cases. Even though I'll have another template specialization for pointers.
When I try to compile this code I get the following errors:
>c:\users\emedeiros\source\repos\test\test\test.cpp(240): error C2079: 'matrix' uses undefined class 'matrix_wrapper<const std::vector<std::vector<double,std::allocator<_Ty>>,std::allocator<std::vector<_Ty,std::allocator<_Ty>>>> &>'
1> with
1> [
1> _Ty=double
1> ]
1>c:\users\emedeiros\source\repos\test\test\test.cpp(240): error C2440: 'initializing': cannot convert from 'const std::vector<std::vector<double,std::allocator<_Ty>>,std::allocator<std::vector<_Ty,std::allocator<_Ty>>>>' to 'int'
1> with
1> [
1> _Ty=double
1> ]
1>c:\users\emedeiros\source\repos\test\test\test.cpp(240): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1
Below you'll find the class definition and a function that will try to create a matrix_wrapper.
#include <vector>
template <class T>
class matrix_wrapper;
template <typename T, class A1, class A2, template <typename, typename> class Cont1, template <typename, typename> class Cont2>
class matrix_wrapper < Cont2 < Cont1 < T, A1>, A2> >
{
public:
typedef typename boost::call_traits<Cont2<Cont1<T, A1>, A2>>::value_type value_type;
typedef typename boost::call_traits<value_type>::param_type param_type;
typedef typename boost::call_traits<value_type>::reference reference;
typedef Cont1<T, A1> vector_type;
typedef typename boost::call_traits<vector_type>::reference vector_type_ref;
typedef typename boost::call_traits<vector_type>::const_reference vector_type_const_ref;
typedef T data_type;
matrix_wrapper(reference data) : m_data(data) {}
inline vector_type_const_ref operator[](size_t i) const
{
return m_data[i];
}
inline vector_type_ref operator[](size_t i)
{
return m_data[i];
}
inline reference data()
{
return m_data;
}
protected:
reference m_data;
};
void test(const std::vector<std::vector<double>>& data)
{
matrix_wrapper<const std::vector<std::vector<double>>&> matrix(data);
}
int main()
{
std::vector<std::vector<int>> v(10, std::vector<int>(10, 1));
test(v);
}
What do I have to change so I can use a const reference as parameter?
I won't directly answer your question, but I dare to guess what you really need to hear :)
First, having references as types of templates is not usually a good idea. If you want to make a wrapper, it makes sense to have a reference on a wrapped inside your class, but it is still better to keep template parameter type to be a value type, not a reference type. Having said that, if you are really sure you want to have reference type as a parameter, you might want to play with std::decay.
Then, I see you have partial template specialization here. From the code you posted it is not clear if you actually need it or not. I personally love to keep things simple, so I'd suggest you're good without it. In this case just parametrize your class on the one and only type T.
As a side note, do not declare your functions inline. Compiler knows best for you. And methods defined in scope of a class are inline by default anyway. Forget that inline means "please make this code faster". This actually means "this symbol might appear in several translation units, please pick a single definition for me".
Finally, boost is a great library, but I don't see how you need it here. All standard containers provide all the necessary type aliases in them, just ask.
Here is the compiling code simplified according to my comments:
#include <vector>
template <class T>
class matrix_wrapper
{
public:
using reference = const T&;
using vector_type_ref = typename T::reference;
using vector_type_const_ref = typename T::const_reference;
matrix_wrapper(reference data) : m_data(data) {}
vector_type_const_ref operator[](size_t i) const
{
return m_data[i];
}
// BTW this won't compile for non-const objects, since you store a const
// reference to the container, but that's a different story
vector_type_ref operator[](size_t i)
{
return m_data[i];
}
reference data()
{
return m_data;
}
protected:
reference m_data;
};
void test(const std::vector<std::vector<int>>& data)
{
matrix_wrapper<std::vector<std::vector<int>>> matrix(data);
}
int main()
{
std::vector<std::vector<int>> v(10, std::vector<int>(10, 1));
test(v);
}
See live demo here: https://wandbox.org/permlink/tmemloS6wCHZlhNY
I see that you declared v in main() as a vector of ints, but you accept a vector of double in test(). I assumed this is a misprint and fixed the types.
I completely agree with #NathanOliver about 1D/2D thing, but that's again a different story.
Is it possible to have a traits in order to convert, let's say, char* to const char* in order to use it further to call functions having const char* parameters using a char* variable?
I have this (the context is large, I've simplified, sorry for the ugly code):
#include <iostream>
using namespace std;
#include <stdio.h>
#include <string.h>
#include <typeinfo>
template<typename T, typename U, std::enable_if_t<std::is_same<T, U>::value, int> = 0>
T convert_type(U _in)
{
return _in;
}
template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_lvalue_reference_t<U>>::value, int> = 0>
T& convert_type(U& _in)
{
return _in;
}
template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_lvalue_reference_t<std::add_const_t<U>>>::value, int> = 0>
T& convert_type(U& _in)
{
return _in;
}
template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_pointer_t<U>>::value, int> = 0>
T convert_type(U& _in)
{
return std::addressof(_in);
}
int main() {
char* c = new char[sizeof "test"];
strcpy(c, "test");
const char * cc = convert_type<const char *, char *>(c); // here not compilable yet due to lack of the right convert_type specialization
cout << c;
delete[] c;
return 0;
}
Just to clarify, I embed SpiderMonkey to script Illustrator API. This made me write pretty complicated code, but I have checked and I know the conversion traits above are in use for various function calls. I've added them here just to see the approach and to clarify the need of adding another that recognizes a type and returns the needed type. All your comments are correct generally, but not in my context. I might have a convoluted code, but I have simplified it as much as I could.
sample code here
As far as it concerns me, the question is not yet answered and I couldn't find a solution. I put the question this way: how to write a traits method to match char* against const char*, which is char const*, actually, when I check in msvc with typeid a type or variable declared as const char*?
Is it possible to have a traits in order to convert, let's say, char* to const char* in order to use it further to call functions having const char* parameters using a char* variable?
As pointed out in the comments, a traits conversion isn't needed at all, since a char* pointer can be used equally as a const char* pointer at any time, since the conversion is implicit (same for any other type than char).
Note that the line in your main() function
char * c = "test";
isn't valid c++ syntax. "test" actually is a const char [5] type and you can't assign that to other than a const char* pointer legally.
At least any attempt to write a value to that pointer will be undefined behavior.
Most c++11 compliant compilers will issue a warning on that statement.
As for your edited example now
char* c = new char[sizeof "test"];
strcpy(c, "test");
//const char * cc = convert_type<const char *, char *>(c);
there's no need for using the convert_type() traits function, you can simply write (as also mentioned in the comments):
const char * cc = c;
(To 'defend' OP: yes, I also thought of simply adding const, since const const T is the same as const T, but, on the other hand, I can think of situations, where you have to pass a type trait that does nothing else but this.)
How about:
// ordinary way w/o type aliases
template<typename T>
struct const_qualify
{
typedef const T type;
};
// do this if you have type aliases
template<typename T>
using const_qualify_t = const T;
Note that, if you just want to compare types, we have now remove_const<> / remove_cv<>: http://en.cppreference.com/w/cpp/types/remove_cv
EDIT: actually, we also have std::add_const<>.
Just use assignment:
const char* cc = c;
(with the caveat that char* c = "test" is ill-formed)
To be more explicit, which is never a bad thing, you can use one of the standard C++ casts:
auto cc = static_cast<const char*>(c);
Your first three convert_type() overloads are basically useless - all of them can be trivially substituted by simply using =. And = actually handles more cases than your convert_type() too.
The fourth overload should be substituted in favor of just & (or directly using std::addressof), there's really no need to hide that you're taking the address. Certainly T* x = &y is a lot easier to understand the meaning of than T* x = convert_type<T*>(y).
Eventually, I've made it, using this post:
template<typename T> struct remove_all_const : std::remove_const<T> {};
template<typename T> struct remove_all_const<T*> {
typedef typename remove_all_const<T>::type *type;
};
template<typename T> struct remove_all_const<T * const> {
typedef typename remove_all_const<T>::type *type;
};
template<typename T, typename U, std::enable_if_t<std::is_same<typename remove_all_const<T>::type, typename remove_all_const<U>::type>::value, int> = 0>
T convert_type(U& _in)
{
return _in;
}
A big Thank! to that post solver!
I'm trying tow write a SFINAE template to determine whether two classes can be added together. This is mostly to better understand how SFINAE works, rather than for any particular "real world" reason.
So what I've come up with is
#include <assert.h>
struct Vec
{
Vec operator+(Vec v );
};
template<typename T1, typename T2>
struct CanBeAdded
{
struct One { char _[1]; };
struct Two { char _[2]; };
template<typename W>
static W make();
template<int i>
struct force_int { typedef void* T; };
static One test_sfinae( typename force_int< sizeof( make<T1>() + make<T2>() ) >::T );
static Two test_sfinae( ... );
enum { value = sizeof( test_sfinae( NULL ) )==1 };
};
int main()
{
assert((CanBeAdded<int, int>::value));
assert((CanBeAdded<int, char*>::value));
assert((CanBeAdded<char*, int>::value));
assert((CanBeAdded<Vec, Vec>::value));
assert((CanBeAdded<char*, int*>::value));
}
This compiles for all except the last line, which gives
finae_test.cpp: In instantiation of ‘CanBeAdded<char*, int*>’:
sfinae_test.cpp:76: instantiated from here
sfinae_test.cpp:40: error: invalid operands of types ‘char*’ and ‘int*’ to binary ‘operator+’
So this error is kind-of what I'd expect, but I'd expect the compiler to then find the test_sfinae( ... ) definition and use that instead (and not complain about the one that doesn't parse.
Clearly I'm missing something, I just don't know what it is.
It looks to me like you've run into the problem that's discussed in Core Issue 339 as well as N2634. The bottom line is that you're pushing a bit beyond what any compiler can currently handle, even though what you're doing is allowed by the standard. C++ 0x will add more detail about what will and won't result in SFINAE failure versus a hard error. See N3000, §14.9.2, if you want to get into the gory details.
I am implementing an n-dimensional array class which is a template as follows (Note that the data is stored in a linear array whose length is the product of all the dimensions):
template< class valType, int rank >
class NDimensionalArray
{
public:
private:
valType* m_data;
int* m_dimensions;
int m_rank;
};
So the idea is that a user (me) can specify an array of rank 2, and of a certain dimension, ie:
NDimensionalArray<double,2> matrix(10,10);
Now the difficulty is in specializing constructors for 1->n dimensions, each constructor takes n parameters where n is the rank of the array. Now I thought of using a valarray like is used in printf(), however with this defining a 1-dimensional array with 2 dimensions ie:
NDimensionalArray<double,1> matrix(10,10);
would be perfectly acceptable behavior. Is there some neat trick I can use to let the compiler do the repetition? Realistically so long as I know the rank, and have the length of each dimension the constructor can be generic:
{
int nElements = m_dimensions[0];
for ( int i=1 ; i<m_rank ; ++i )
nElements *= m_dimensions[i];
m_data = new valType[nElements];
}
Edit: Note that a similar operation will be needed for accessors.
Also I have considered the option of a constructor which looks like:
NDimensionalArray( const NDimensionalArray<int,1>& dimensions );
Which could be used like:
NDimensionalArray<int,1> dimVec(2); // Need a specification for 1-dimensional arrays.
dimVec(0) = 10;
dimVec(1) = 10;
NDimensionalArray<double,2> matrix(dimVec);
This would be a viable solution, but its ugly compared to the use I would like. Also accessing multi-dimensional arrays would become a serious pain, and seriously slow having to construct a dimension vector for each access.
Okay, I've played with this for a while. Here's some template metaprogramming hackery that does something close to what you want. It lets you specify all dimensions inline, it doesn't do any dynamic memory allocation or other such things. In addition, with a good C++ compiler (I tested with VC++ /O2 option), the code will be fully inlined, with no copies done (in fact, for me it inlined the whole NDimensionalArray constructor at the point of the call). It will typecheck completely at compile-time, and won't let you pass too few or too many dimensions. And it can be reused for indexers. Here goes:
template<class T, int N>
class value_pack : private value_pack<T, N-1>
{
public:
enum { size = N };
value_pack(value_pack<T, N-1> head, const T& tail)
: value_pack<T, N-1>(head)
, value(tail)
{
}
value_pack<T, N+1> operator() (const T& tail) const
{
return value_pack<T, N+1>(*this, tail);
}
template<int I>
const T& get() const
{
return this->value_pack<T, I+1>::value;
}
protected:
const T value;
};
template<class T>
struct value_pack<T, 0>
{
};
struct
{
template <class T>
value_pack<T, 1> operator() (const T& tail) const
{
return value_pack<T, 1>(value_pack<T, 0>(), tail);
}
} const values;
template <class ValType, int Rank>
struct NDimensionalArray
{
NDimensionalArray(value_pack<ValType, Rank> values)
{
// ...
}
};
int main()
{
NDimensionalArray<int, 3> a(values(1)(2)(3));
}
I think the best solution is to take a vector of ints and let the constructor validate it against the template parameter 'rank'.
NDimensionalArray matrix(std::vector<int> matrixDimensions)
{
if (matrixDimensions.size() != rank)
{
throw SomeException();
}
...
}
I don't think any compiler trick can be an alternative here. (Except perhps using macros, if you can think of something, although that wouldn't be a compiler trick strictly speaking.)
Not a direct answer, but check out the blitz library.
There's no good way to do it in C++ as currently standardized. In C++0x, you'll be able to use template parameter packs to approximate (I think I've got the syntax right, but not sure about expansion in requires):
template <class ValType, int Rank>
struct NDimensionalArray
{
template <class... Args>
requires std::SameType<Args, ValType>... && std::True<sizeof...(Args) == Rank>
NDimensionalArray(Args... values)
{
...
}
};
You could take a std::tr1::array. Hmm:
#include <array>
template< class valType, int rank >
class NDimensionalArray
{
public:
NDimensionalArray(const std::tr1::array<rank>& dims);
// ...
};
NDimensionalArray<double,2> foo({10,10});
NDimensionalArray<double,2> bar({10}); // second dimension would be 0
NDimensionalArray<double,1> baz({10,10}); // compile error?
I'm not actually sure if that works! I'll run it through comeau.
Edited As per the comments, looks like this approach would look more like:
std::tr1::array<2> dims = {10, 10};
NDimensionalArray<double,2> foo(dims);
Boost has a multi-array library that uses a custom object for constructing their multidimensional array. It's a really good way to do it; I suggest you study (or better yet, use) their code.