Can I have partial template specialization with the using keyword? - c++11

In the code of the OpenCV library I find this:
template<typename _Tp, int cn> class Vec
{
...
}
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
I would like to have a Vec of type float and variable length N. Is it possible to write something like
using Vecf<N> = Vec<float, N>;
?

Yes, and you are nearly there.
The correct syntax would be
template<int N>
using Vecf = Vec<float, N>;

Related

Is it possible to use eigen 3.3.3 on Windows with __ARM_NEON__ defined?

When I try to use Eigen 3.3.3 on Windows with __ARM_NEON__ defined, I get the following compilation error (followed by a bunch of similar ones):
eigen\src/Core/arch/NEON/PacketMath.h(109): error C2766: explicit specialization; 'Eigen::internal::unpacket_traits<Eigen::internal::Packet4f>' has already been defined
The code around this error looks like this:
template<> struct unpacket_traits<Packet4f> { typedef float type; enum {size=4, alignment=Aligned16}; typedef Packet4f half; };
template<> struct unpacket_traits<Packet4i> { typedef int32_t type; enum {size=4, alignment=Aligned16}; typedef Packet4i half; };
Packet4f and Packet4i are defined (in PacketMath.h) as:
typedef float32x4_t Packet4f;
typedef int32x4_t Packet4i;
And float32x4_t and int32x4_t are defined (in MSVC's arm_neon.h) as:
typedef __n128 float32x4_t;
typedef __n128 int32x4_t;
So the compilation error makes sense, but is this supposed to work somehow with Eigen 3.3.3, or is this a bug? Any suggested workarounds, other than disabling vectorization (via EIGEN_DONT_VECTORIZE)?

Cannot convert from 'const std::initializer_list<_Elem>' to 'const std::allocator<_Ty>' where both templates are int

5> ...long path...\PredicateEquals.cpp(47): error C2664: 'std::vector<_Ty>::vector(const std::allocator<_Ty> &)' : cannot convert parameter 1 from 'const std::initializer_list<_Elem>' to 'const std::allocator<_Ty> &'
5> with
5> [
5> _Ty=int
5> ]
5> and
5> [
5> _Elem=int
5> ]
5> and
5> [
5> _Ty=int
5> ]
5> Reason: cannot convert from 'const std::initializer_list<_Elem>' to 'const std::allocator<_Ty>'
5> with
5> [
5> _Elem=int
5> ]
5> and
5> [
5> _Ty=int
5> ]
5> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Note that both _Elem=int and _Ty=int so basically what fails is conversion from const std::initializer_list<int> to const std::vector<int>. I thought this was the very purpose of initializer lists - to convert them into arrays.
I based my code on this answer:
Header file
#include <initializer_list>
#include <vector>
class Indexes {
public:
Indexes(const std::initializer_list<int> uniqueIds);
protected:
const std::vector<int> uniqueIds_;
};
Source file:
Indexes::Indexes( const std::initializer_list<int> uniqueIds )
:
uniqueIds_(uniqueIds)
{}
The error comes from the source file, from the second constructor. How to properly use the initializer list for the constructor here? I'd prefer to keep std::vector a constant. But removing the const did not remove the problem.
I am using Microsoft Visual Studio 2010. The code compiles perfectly in GCC: http://ideone.com/HRC68a
You could try:
#include <initializer_list>
#include <vector>
class Indexes {
public:
#ifdef PRE_CXX11_COMPILER
template<typename... T>
Indexes(T... t) : uniqueIds_{t...} { }
#else
Indexes(const std::initializer_list<int> uniqueIds) : uniqueIds_{uniqueIds} { }
#endif
protected:
const std::vector<int> uniqueIds_;
};
But I have no idea if that will work with MSVC 2010 either.
If you can't change your toolchain then you need to avoid C++ 2011 features that a 2010 compiler doesn't support.
So far, only thing I have is a workaround that uses plain old C varargs feature. This is nothing like initializer lists and requires you pass -1 as last parameter. I do not recommend using this if you can upgrade your compiler. Failing to pass correct parameters results in segmentation fault. But in my case rot of repetitive unreadable code would ensue if instead filled vectors manually using std::vector::push_back.
Header file
#include <vector>
#ifdef CPP_11_COMPILER
#include <initializer_list>
#else
#include <stdarg.h>
#endif
class Indexes {
public:
// Constructor with standard vector
Indexes(const std::vector<int>& uniqueIds);
#ifdef CPP_11_COMPILER
Indexes(const std::initializer_list<int> uniqueIds);
#else
// Static method to construct the std::vector and then the class' instance
// ☠☠☠ WARNING: variadric arguments must be of type short! Last argument MUST BE -1!!!
static Indexes with_initializer_list(const int unused, ...);
#endif
protected:
const std::vector<int> uniqueIds_;
};
Source file
Indexes::Indexes( const std::vector<int>& uniqueIds )
: uniqueIds_(uniqueIds)
{}
#ifdef CPP_11_COMPILER
Indexes::Indexes( const std::initializer_list<int> uniqueIds )
: uniqueIds_(uniqueIds)
{}
#else
Indexes Indexes::with_initializer_list( const int unused, ... )
{
va_list ap;
va_start(ap, unused);
std::vector<int> items;
int entry = 0;
while((entry = va_arg(ap, short))>=0) {
items.push_back(entry);
}
va_end(ap);
return Indexes(items);
}
#endif
Usage
The solution isn't exactly reliable, but is best fit before an upgrade of compiler happens:
Indexes indexes = Indexes::with_initializer_list(0, (short)1,(short)2,(short)3,(short)-1);
// indexes' vector now contains [1, 2, 3]

SFINAE expression fails to compile with clang

This looks like an issue in clang (I've already opened a bug here), but I'd like to be sure that I'm not doing a mistake.
Consider the following code:
#include <type_traits>
#include <cstddef>
template<std::size_t N, std::size_t M, std::enable_if_t<not (N>M)>* = nullptr> // (1)
struct S: public S<N+1, M> { };
template<std::size_t N>
struct S<N, N> { };
int main() {
S<0, 1> c{};
}
It fails to compile with the following error:
8 : error: non-type template argument specializes a template parameter with dependent type 'std::enable_if_t M)> *' (aka 'typename enable_if M), void>::type *')
struct S { };
The same code works as expected using the following line instead of (1):
template<std::size_t N, std::size_t M, typename = std::enable_if_t<not (N>M)>>
The SFINAE expression is almost the same. It is based on a specialization of std::enable_if_t and I would expect the same result (success or failure) for both of the examples.
Are my expectations wrong?
Note that GCC works fine in either cases.
I think this is a gcc bug actually, as a result of [temp.class.spec]:
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
In your example, the type of the 3rd template parameter is dependent on a parameter. When you swap it to typename = std::enable_if_t<...>, then this rule no longer applies.
Note: is there any reason to use SFINAE here anyway, as opposed to static_assert-ing?

g++ fails to look up static functions in a template class, is it a bug or standard defined?

When I try some C++11 code like following, it passed in all clang++ available to me that support C++11, but it failed to compile in g++-4.8, g++-4.9 and g++-5.0.
#include <type_traits>
#include <vector>
template <class C, class First, class Last>
struct HasInsertEnd {
template <class U>
static std::false_type Check(...);
template <class U>
static auto Check(U val)
-> decltype(val.insert(val.end(), std::declval<First>(),
std::declval<Last>()),
std::true_type{});
template <class U>
using Deduce = decltype(Check<U>(std::declval<U>()));
using type = typename Deduce<C>::type;
static constexpr bool value = type::value;
};
int main(int argc, char* argv[]) {
static_assert(!HasInsertEnd<int, int, int>::value, "...");
static_assert(HasInsertEnd<std::vector<int>, const int*, const int*>::value,
"...");
return 0;
}
g++ will report errors like:
‘Check’ was not declared in this scope
If I change the calling of Check in the Deduce to HasInsertEnd::Check, both g++ and clang++ will be happy.
I know little about dependent name lookup. The problem is, which behavior is standard?
This is a bug in GCC, and can be shown to be a bug in GCC even without deferring to the standard.
template <typename T>
struct f { typedef int type; };
template <typename T>
struct S {
template <typename U>
static f<U> f();
template <class U>
using u = typename decltype(f<U>())::type;
using t = u<T>;
};
S<int>::t main() { }
This is rejected the same way in GCC 4.7.4 and GCC 5, with "error: ‘f’ was not declared in this scope". That's just nonsense. Even if the static member function should somehow not be visible, there is still a global type by the same name that would be found instead. It gets even better, though: with that global type, you get:
test.cc: In substitution of ‘template<class T> template<class U> using u = typename decltype (f<U>())::type [with U = T; T = T]’:
test.cc:12:20: required from here
test.cc:10:36: error: ‘f’ was not declared in this scope
using u = typename decltype(f<U>())::type;
^
test.cc:10:36: note: suggested alternative:
test.cc:2:12: note: ‘f’
struct f { typedef int type; };
^
test.cc:15:13: error: ‘t’ in ‘struct S<int>’ does not name a type
S<int>::t main() { }
^
That's right, it's suggesting that f can be corrected by spelling it f.
I don't see any problem with your code, and if it isn't a known bug, I encourage you to report it. and it's been reported as a bug before.
Oddly, as noted in the comments, GCC 4.8.4 and GCC 4.9.2 do find a global f. However, if the global f is a type, then they still reject the program, with "error: missing template arguments" even though the template argument is provided, so it's still clearly a bug in GCC.

Merge two variadic templates in one

Im trying to implement a variadic template wrapper of the loki typelist.
Merging two typelists in loki-style is easy, but im having problems with merge in variadic-template style.
This is my implementation (Simplified, without push_back , index_of , ... , methods).
template<typename... Ts>
struct dl32TypeList;
template<typename HEAD , typename... TAIL>
struct dl32TypeList<HEAD,TAIL...>
{
static const unsigned int size = sizeof...(TAIL) + 1;
using value = dl32Loki_like_TypeList<HEAD, typename dl32TypeList<TAIL...>::value>;
};
template<>
struct dl32TypeList<>
{
using value = dl32NoType;
static const unsignedint size = 0;
};
I want something like:
template<typename OTHER_TYPELIST>
using merge = dl32TypeList<HEAD , TAIL... , typename OTHER_TYPELIST::???>;
And this is the problem: We cannot store variadic template args as a using/typedef, so i have any idea about how i can do this. (Note the OTHER_TYPELIST::???).
I don't know what Loki or DL32 are, and it's not clear you should be implementing anything at all.
std::tuple is a common tool for type lists. It is designed as a runtime storage container but works as a compile-time utility as long as the types are complete. Here is one way to catenate tuples:
template< typename ... t >
struct tuple_cat
{ typedef decltype( std::tuple_cat( std::declval< t >() ... ) ) type; };
If you want to do it manually, try partial specialization:
template< typename ... t >
struct type_list {};
template< typename ta, typename tb >
struct type_cat;
template< typename ... a, typename ... b >
struct type_cat< type_list< a ... >, type_list< b ... > >
{ typedef type_list< a ..., b ... > type; };
As for the size member, you can make a universal metafunction to solve the problem once and for all.
template< typename >
struct count_types;
template< template< typename ... > class t, typename ... a >
struct count_types< t< a ... > >
{ static constexpr std::size_t value = sizeof ... a; };

Resources