【问题标题】:std::enable_if to choose a class specialitzationstd::enable_if 选择一个类专业化
【发布时间】:2021-10-18 15:59:14
【问题描述】:

我很想了解std::enable_if 以及使用它而不是static_assert / regular template specialitzation. 的好处

看了一圈发现:

这对于在不满足特定条件时在编译时隐藏签名很有用,因为在这种情况下,将不会定义成员 enable_if::type 并且尝试使用它进行编译应该会失败。 http://www.cplusplus.com/reference/type_traits/enable_if/

然后我的问题是:为什么编译器指责我说 C 类已经声明了?,当一次只有一个声明应该可用时。

class Interface{};

class Foo : public Interface{};

template <class T, typename = typename std::enable_if<std::is_base_of<Interface,T>::value>::type>
class C{
   // Some custom implementation
}

template <class T, typename = typename std::enable_if<!std::is_base_of<Interface,T>::value>::type>
class C { 
  //Some fallback / default implementation
}

int main() {
    C<Foo> myVariable;
}

Godbolt 中的相同行为:https://godbolt.org/z/cbfhG9q54

提前致谢!

【问题讨论】:

  • 类模板不能重载
  • 例如,如果您决定显式指定模板的第二个参数的值:C&lt;int, void&gt; ambiguousClass;,那么编译器应该使用哪个版本的C?它甚至不必尝试计算enable_if&lt;is_base_of&lt;Interface, int&gt;&gt;,因为您已经告诉它您将使用void,而不是该参数的默认值。
  • 它可以用于类模板专业化template&lt;typename T&gt; class C&lt;T, std::enable_if&lt;whatever&gt;&gt; {...}
  • 它仍然可以得到你想要的效果,只是不完全是你使用它的方式。参见例如herehere 用于 C++20 版本。
  • 此错误在the cppreference notes for std::enable_if 中被描述为“常见错误”。

标签: c++ templates typetraits enable-if


【解决方案1】:

你不能像函数模板那样重载类模板,购买你可以部分专门化它们(你不能用函数模板做到这一点):

#include <ios>
#include <iostream>
#include <type_traits>

class Interface
{};
class Foo : public Interface
{};

template <class T, typename = void>
struct C
{
    // Some default impl.
    static constexpr bool is_default_impl{true};
};

template <class T>
struct C<T, std::enable_if_t<std::is_base_of_v<Interface, T>>>
{
    // Some custom implementation.
    static constexpr bool is_default_impl{false};
};

int main()
{
    std::cout << std::boolalpha 
        << C<int>::is_default_impl << " "  // true
        << C<Foo>::is_default_impl;        // false
}

请注意,此示例需要 C++17 用于变量模板 std::is_base_of_v,它是 value 特征的 value 成员的简写常量,别名模板 std::enable_if_t 需要 C++14 ,它为std::enable_if trait 的type 成员别名声明起别名。

【讨论】:

  • 在人们做了所有的 cmets 之后,我得到了相同的解决方案。感谢您编写它,我相信它会在未来帮助某人!
  • 当心 MSVC 中的一些晦涩的错误,如果主模板针对给定的模板参数进行编译,则可能会跳过部分特化。最好将主模板保留为纯前向声明,并确保专业化不会在其 enabled_if 子句中重叠...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-12
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多