简体   繁体   English

带有 enable_if 的模板 class 外的方法

[英]Method outside template class with enable_if

I have the following code where I want a template class to check the template value as one of int64_t or unint64_t upon init.我有以下代码,我想要一个模板 class 在初始化时将模板值检查为int64_tunint64_t之一。 The class has a GetValue method that is implemented outside the class. class 具有在 class 外部实现的GetValue方法。

template <typename T, typename std::enable_if<std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>>::type>
class Class
{
public:
    Class(T value) noexcept :
        cachedValue(value) {}

    T GetValue() noexcept;

private:
    T cachedValue;
};

template <typename T>
T Class<T>::GetValue() noexcept
{
    // placeholder for now.
    return cachedValue;
}

However, I am running into build errors C2955 , C2956 , C2976 or something similar from the enable_if even after trying several ideas from other SO posts.但是,即使在尝试了其他 SO 帖子的几个想法之后,我也遇到了来自enable_if的构建错误C2955C2956C2976或类似的东西。 How do I get this working?我如何让这个工作?

Issue with问题

template <typename T,
          typename std::enable_if<std::is_same_v<T, int64_t>
                               || std::is_same_v<T, uint64_t>>::type>
class Class;

is that is result into那是结果

template <typename T_OK, void> class Class;

or或者

template <typename T_KO, /*Subsitution failure*/> class Class;

Which are both incorrect.这两个都不正确。

For non-friendly cases, (which might be enough most of the time), you might simply use static_assert :对于不友好的情况(大多数情况下可能就足够了),您可以简单地使用static_assert

template <typename T> class Class
{
    static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>);
    /// ...
};

Else there are several variation (I will shorter the condition to cond_v<T> )否则有几种变化(我会将条件缩短为cond_v<T>

  • Common one:(:常见的:(:

     template <typename T, typename = std::enable_if_t<cond_v<T>>> class Class { ///... }; Class<int64_t> ok; Class<float> ko; // doesn't compile, as expected // but might be hijacked: Class<float, void> hijacked; // compile, unexpected
  • Fixed:固定的:

     template <typename T, std::enable_if_t<cond_v<T>, int> = 0> class Class { ///... }; Class<int64_t> ok; Class<float> ko; // doesn't compile, as expected
  • One which allow customization一种允许定制的

    template <typename T, typename = void> class Class; template <typename T> class Class<T, std::enable_if_t<cond_v<T>>> { ///... }; Class<int64_t> ok; Class<float> ko; // incomplete type: doesn't compile, as expected // user might add additional specialization: template <typename T> class Class<std::vector<T>, void> {/*..*/};

    mostly useful to create customizable traits (as you specialize whole class).最适用于创建可定制的特征(因为您专门研究整个班级)。

C++20 introduces concept which shorter and simplify syntax: C++20 引入了更短和简化语法的概念:

  • restreint allowed type (there are several equivalent syntax) restreint 允许的类型(有几种等效的语法)

     template <typename T> requires(cond_v<T>) class Class { /*..*/};
  • Allow customization, take best specialization:允许定制,采取最好的专业化:

     template <typename T> class Class; // Specialization template <typename T> requires(cond_v<T>) class Class<T> { /*..*/};

You can use @WhozCraing method, use a static_assert to provide some message/instruction or use Concepts with C++20 , as follows您可以使用 @WhozCraing 方法,使用static_assert提供一些消息/指令或使用C++20Concepts ,如下所示

template<class T>
concept ints64 = std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>;
template <typename T> requires(ints64<T>)
struct Class{
    Class(T value) noexcept : cachedValue(value) {}
    T GetValue() noexcept;

private:
    T cachedValue;
};

template <typename T>requires(ints64<T>)
T Class<T>::GetValue() noexcept{
    return cachedValue;
}

int main(){
    return Class<int64_t>{0}.GetValue();//return Class<int>{0}.GetValue(); won't compile

}

there is also a traditional way to make class template SFINAE-friendly before C++20:在 C++20 之前,还有一种使 class 模板对 SFINAE 友好的传统方法:

template<typename T, typename = void>
class Class; // <1> you can define it here if the conditions are not satisfied.

template<typename T>
class Class<T, typename std::enable_if<std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>>::type>{
public:
    Class(T value) noexcept :cachedValue(value) {}

    T GetValue() noexcept;

private:
    T cachedValue;
};

int main(){
    Class<int64_t> a = 0; // ok
    Class<uint64_t> b = 0; // ok
    Class<int32_t> c = 0; // incomplete-type. you can define it at <1>.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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