简体   繁体   中英

Using non-type template argument during partial specialization

Consider the following struct s:

//Implementations provided elsewhere

struct A {  A(int i, double d, std::string s);  /* ... */ };
struct B {  B(double d1, double d2);            /* ... */ };

I have two conversion classes whose template signatures look like:

TupleAs< A, int, double, std::string > via1 { ... };
ArrayAs< B, double, 2 >                via2 { ... };

Predictably, TupleAs converts a triplet of int , double , and std::string values into an object of type A . Similarly, ArrayAs converts a pair of two double values into an object of type B . (And yes, there are reasons why I cannot call the A and B constructors directly.)

Improving the syntax

I would like to change the syntax so I can do the following:

TupleAs< A(int,double,std::string) > via1 { ... };
ArrayAs< B(double,2) >               via2 { ... };

which, I think, is more descriptive of a conversion process. The TupleAs template declaration and corresponding partial specialization would look like this:

template <typename T> struct TupleAs;

template <typename T, typename ... Args>
struct TupleAs<T(Args...)> { ... };

Compiler errors

However, if I try to do something similar with the ArrayAs version:

template <typename T> struct ArrayAs;

template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };

I get the following errors in clang (3.6) when trying to instantiate it ( ArrayAs< B(double,2)> test; ):

typeAs.cpp:14:22: error: unknown type name 'N'
  struct ArrayAs<T(U,N)>{
                     ^
typeAs.cpp:14:10: warning: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
  struct ArrayAs<T(U,N)>{
         ^~~~~~~~~~~~~~~
typeAs.cpp:13:45: note: non-deducible template parameter 'N'
  template<typename T, typename U, unsigned N>
                                            ^

The gcc error diagnostic is a little different, but I won't post it here.

I admit that my templating skills should be better than they are, and I also concede that an analogous std::function<B(double,2)> declaration clearly is nonsense. But can someone tell me why the particular syntax I'm trying to achieve is not allowed? I looked through the C++14 standard and had trouble finding the relevant portion, and I'm having trouble interpreting the clang diagnostic message.

When you specialize TupleAs :

template <typename T, typename ... Args>
struct TupleAs<T(Args...)>

You are basically overloading the notation for a function. You are specializing on a function that takes Args... and returns a T . That is a type. You may not be using that function as a function, or really ever think about it as being a type, but that is what it is.

On the other hand, here:

template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };

There is no such thing as a function that takes N . It could take unsigned , but it can't take a value . There is just no such reasonable thing. From your example, B(double, 2) simply does not make sense. At best, you could write something that would allow:

template <unsigned N> using size_ = std::integral_constant<size_t, N>;

ArrayAs< B(double,size_<2>) >

Or even:

ArrayAs< B(std::array<double, 2>) >

since now we're back to using types everywhere. Whether you prefer that or not is personal preference.

The key here is that types are first-class citizens when it comes to all things template metaprogramming, and values should be avoided where possible.

template <typename T> struct ArrayAs;

template <typename T, typename U, std::size_t N>
struct ArrayAs<T(std::array<U,N>)> { ... };

works, as would:

template<class T>
struct to_array;
template<class T, size_t N>
struct to_array< T[N] > { using type = std::array<T, N>; };
template<class T>
using arr = typename to_array<T>::type;

then:

ArrayAs< Bob( arr<int[3]> ) > some_var;

live example .

Sadly, directly using ArrayAs< Bob( int[3] ) > doesn't work due to how arrays in function types decay to pointers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM