SFINAE:启用 class 构造函数

SFINAE: Enable class constructor

我有一个 "parameter" class 可以选择将 "identification group type" 作为模板参数 typename IDENTIFICATION_GROUP:

struct ConstrainedParameterIdentification_None {};

template<typename UNIT_TYPE, typename DATA_TYPE = double, typename IDENTIFICATION_GROUP = ConstrainedParameterIdentification_None>
class Parameter
{
    /* Constructor - the only method taking care about valid IDENTIFICATION_GROUP */
    template<typename = std::enable_if<!std::is_same<IDENTIFICATION_GROUP, ConstrainedParameterIdentification_None>::value>>
    Parameter( const typename IDENTIFICATION_GROUP::IDType ID )
    { /* ... */ }
};

在实例化参数 class 时,使用了如下所列的 class 类型(有趣的部分是 using IDType = int;):

struct SampleIdentificationGroup
{
    using IDType = int;
    /* ... */
};

除非我像这样实例化参数:

Parameter<si::length, double, SampleIdentificationGroup> Param;

一切正常。

但是一旦我想使用默认值IDENTIFICATION_GROUP - ConstrainedParameterIdentification_None,我的麻烦就来了。我的第一次尝试是在 ConstrainedParameterIdentification_None 中也简单地定义 IDType 但由于副作用,它不是解决方案。因此我想 enable/disable 参数成员方法使用 IDENTIFICATION_GROUP "internals (typedefs...)".

所以我尝试将 SFINAE 应用于 enable/disable 我的构造函数(唯一关注 IDENTIFICATION_GROUP“内部”的方法):

template<typename = std::enable_if<!std::is_same<IDENTIFICATION_GROUP, ConstrainedParameterIdentification_None>::value>>
Parameter( const typename IDENTIFICATION_GROUP::IDType ID )
{ /* ... */ }

在人类语言中,我试图达到的是“If IDENTIFICATION_GROUP is ConstrainedParameterIdentification_None,排除整个方法。”。

但是 GCC 抱怨类型 IDType 没有被定义:

error: no type named ‘IDType’ in ‘struct Base::ConstrainedParameterIdentification_None’
   Parameter( const typename IDENTIFICATION_GROUP::IDType ID )

但是由于 SFINAE,Parameter( const typename IDENTIFICATION_GROUP::IDType ID ) 应该从构建中省略,对吧?那么为什么会有这样的抱怨呢?我做错了什么?

非常感谢任何愿意提供帮助的人...

干杯马丁

问题是您试图将不存在的类型传递给 std::enable_if。为了解决这个问题,您可以轻松地想出自己的 enable_if:

版本
template <typename IDENTIFICATION_GROUP = ConstrainedParameterIdentification_None> struct my_enable_if {
    using type = typename IDENTIFICATION_GROUP::IDType;
};
template <> struct my_enable_if<ConstrainedParameterIdentification_None> {

};

template<typename IDENTIFICATION_GROUP = ConstrainedParameterIdentification_None> class Parameter {
    public:
        template <typename Unused = IDENTIFICATION_GROUP>
        Parameter(typename my_enable_if<Unused>::type ID) { }
        Parameter() { }

};

SFINAE 需要虚拟 Unused 模板参数才能工作(相关方法必须至少依赖于一个模板参数)。

我想您可以按以下方式简单地编写构造函数

template <typename IG = IDENTIFICATION_GROUP>
   Parameter (typename std::enable_if<false == std::is_same<IG, ConstrainedParameterIdentification_None>::value, typename IG::IDType>::type const ID)
{ /* ... */ }

如果你可以使用 C++14,std::enable_it_t 应该避免烦人的 typename 和烦人的 ::type,所以

template <typename IG = IDENTIFICATION_GROUP>
   Parameter (std::enable_if_t<false == std::is_same<IG, ConstrainedParameterIdentification_None>::value, typename IG::IDType> const ID)
{ /* ... */ }