The default parameter in the template & # 8594; the template argument includes a template parameter

I have a problem similar to this: SFINAE using bool gives compiler error: "template argument 'T :: value includes template parameter"

I want to define a trait that indicates if the complex representation is an array of structures where the real values ​​are never AoS, so no user-defined spec is required, but for complex you will always need:

/**
 * 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 std-way by outputting from std :: true / false_type.

The problem is this: with this implementation I get the "template argument associated with the template parameter" (which is explained in the linked question), but if I switch to types (ommit ":: value" in the first template and change true to true_type in the second ). Complex types will no longer match the second pattern because only output from std :: true_type and ARE NOT std :: true_type.

The only solution I can think of is to use the SFINAE expression and change the second parameter of the main template to default void and enable_if for the real case (isComplex == false). Anything better?

+3


source to share


2 answers


Assuming the IsAoS<T>

desired behavior:

  • If IsComplex<T>::value

    - false

    , it defaults to false_type

    ;
  • Otherwise, it is an error if the user does not provide a specialization.

Simple execution with static_assert

; no default template argument required:

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 to use the default arguments argument, 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

.

+2


source


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 the 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

+2


source







All Articles