3

I have a problem similar to this one: SFINAE tried with bool gives compiler error: "template argument ‘T::value’ involves template parameter"

I want to define a trait that tells if a complex representation is an array of structs, where real values are never AoS hence no user defined specilization should be required, but for complex you'd always need one:

/**
 * Evaluates to a true type if the given complex type is an Array of Structs, false otherwise
 * Defaults to false for Real values
 */
template< typename T, bool T_isComplex = IsComplex<T>::value >
struct IsAoS: std::false_type{};

/**
 * Undefined for (unknown) complex types
 */
template< typename T >
struct IsAoS< T, true >;

Specializations are done in the std-way by deriving from std::true/false_type.

The problem is: With this implementation I get the "template argument involves template parameter(s)" error (which is explained in the linked question) but if i switch to types (ommit "::value" in first template and change true to true_type in 2nd) Complex types won't match the 2nd template anymore because the only derive from std::true_type and ARE NOT std::true_type.

Only solution I can think of is using expression SFINAE and change the 2nd parameter of the main template to default void and an enable_if for the real case (isComplex==false). Anything better?

Community
  • 1
  • 1
Flamefire
  • 5,313
  • 3
  • 35
  • 70
  • 1
    [Your code should be fine as is](http://coliru.stacked-crooked.com/a/cb2dee9c0e1ff3ed), and this is actually a fairly common technique. Which compiler are you using, and which version? – T.C. Jun 02 '15 at 08:42
  • Well, you modified the code to make IsAoS default to true for all complex types which is wrong/dangerous. My example: http://coliru.stacked-crooked.com/a/086450479bc561db – Flamefire Jun 02 '15 at 08:58
  • The compiler's point is that you can't write `struct IsAoS< std::complex >` and use the default template argument of the primary template to fill in the second argument for that partial specialization, because that depends on `T` and so is not allowed. (The code snippet that causes an error should really be in your question.) What's the desired behavior - defaults to `false_type`, unless `IsComplex::value` is `true`, in which case it should be an error unless the user provides a specialization? – T.C. Jun 02 '15 at 18:04

2 Answers2

3

On the assumption that IsAoS<T>'s desired behavior is:

  • If IsComplex<T>::value is false, it defaults to false_type;
  • Otherwise, it is an error unless the user provides a specialization.

It's straightforward to implement with a static_assert; no default template argument needed:

template< typename T >
struct IsAoS: std::false_type {
    static_assert(!IsComplex<T>::value, "A user specialization must be provided for Complex types");
};

If you want the default argument trickery, just use a wrapper layer:

namespace detail {

    template< typename T, bool T_isComplex = IsComplex<T>::value >
    struct IsAoS_impl: std::false_type{};

    /**
     * Undefined for (unknown) complex types
     */
    template< typename T >
    struct IsAoS_impl< T, true >;
}

template<class T> struct IsAoS : detail::IsAoS_impl<T> {};

Users should just specialize IsAoS.

T.C.
  • 133,968
  • 17
  • 288
  • 421
2

If I understand correctly, you want:

template<class> struct IsComplex_impl  {using type = std::false_type;};
template<class T> struct IsComplex_impl<std::complex<T>> {using type = std::true_type;};

template <typename T>
using IsComplex =  typename IsComplex_impl<T>::type;

// Declaration only
template<typename T, typename T_isComplex = IsComplex<T>>
struct IsAoS;

// general case
template< typename T >
struct IsAoS< T, std::false_type >: std::false_type{};

// specialization for complex<double>
template<>
struct IsAoS< std::complex<double>>: std::true_type{};

Live Demo

or with same signature:

template<class> struct IsComplex_impl : std::false_type {};
template<class T> struct IsComplex_impl<std::complex<T>> : std::true_type {};

template <typename T>
constexpr bool IsComplex() {return IsComplex_impl<T>::value;}

// Declaration only
template<typename T, bool T_isComplex = IsComplex<T>()>
struct IsAoS;

// general case
template< typename T >
struct IsAoS< T, false>: std::false_type{};

// specialization for complex<double>
template<>
struct IsAoS< std::complex<double>>: std::true_type{};

Live Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • This does not change the problem: http://coliru.stacked-crooked.com/a/a6e11b72a78d52fc – Flamefire Jun 02 '15 at 10:00
  • @Flamefire: Compilation fixed by changing prototype of `IsAoS`. – Jarod42 Jun 02 '15 at 10:14
  • First version does work although the nested type ssems quite ugly when once could just inherit from true/false_type. However I could change the using to use a new instance of integral_type which should work(?) 2nd version does not work with partial specializations (complex) – Flamefire Jun 02 '15 at 14:39