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?
source to share
Assuming the IsAoS<T>
desired behavior:
- If
IsComplex<T>::value
-false
, it defaults tofalse_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
.
source to share
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{};
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{};
source to share