【问题标题】:Why does this std::enable_if not work为什么这个 std::enable_if 不起作用
【发布时间】:2016-11-08 20:59:57
【问题描述】:

从这个问题Why should I avoid std::enable_if in function signatures看来我应该可以写

#include <type_traits>
#include <iostream>

enum Class {
    Primary,
    Secondary
};

template<Class C>
class Entity {
public:
    template<typename Cls = C, typename Sec = Secondary, std::enable_if<std::is_same<Cls, Sec>::value>::type = 0>
    void onlyLegalForSecondaryEntities() {
        std::cout << "Works" << std::endl;  
    }
};

int main() {
    Entity<Secondary> e;
    e.onlyLegalForSecondaryEntities();
    return 0;
}

但是编译失败并出现错误prog.cpp:13:7: note: template argument deduction/substitution failed

如何编译这段代码?

【问题讨论】:

  • Secondary 不是类型
  • 如何将Entity 的模板参数限制为具有类型的主要或次要类型?
  • @shane,您似乎对基本的 C++ 概念有很大的误解。我建议你choose a book,学习它,一旦你掌握了基础知识再回来。
  • @StoryTeller 没有帮助。如果您可以在枚举上进行模板化,那么当 std::is_same 用作模板参数时不会评估枚举和类型之间的相同性,这是一个完全合理的误解。
  • @shane,将类型与值进行比较是合理的!?我支持我所说的。回归基础。

标签: c++ c++11 templates sfinae typetraits


【解决方案1】:

您将Class 用于enum 是一个可怕的想法。不要使用大小写不同的语言关键字作为类型名称。

CClass 类型的编译时值。它不是一个类型。

typename Cls = C 尝试将 Class 类型的值分配给一个类型。这是一个类似于说“拿起悲伤”的错误。 sad 不是名词,也不是你能捡起来的东西。

使代码编译的最简单方法是完全删除onlyLegalForSecondaryEntities,以及对它的所有引用。

一般而言,根据标准,您不能拥有仅在将某些参数传递给它所在的模板类时才有效的模板方法。这样做会使您的程序不正确,不需要诊断。

这很接近:

template<Class Cls = C,
  std::enable_if_t< Cls == Secondary, int> =0
>
void onlyLegalForSecondaryEntities() {
    std::cout << "Works" << std::endl;  
}

除了Entity&lt;Primary&gt;,您也可以使用.onlyLegalForSecondaryEntities&lt;Secondary&gt;()

如果您不想允许这样做,我会使用 CRTP。

template<bool b, class D>
struct empty_if_false {};

template<class D>
struct empty_if_false<true, D> {
  D* self() { return static_cast<D*>(this); }
  D const* self() const { return static_cast<D*>(this); }
  void onlyLegalForSecondaryEntities() {
    // use self() instead of this in this method to get at a this pointer
    std::cout << "Works" << std::endl;  
  }
};

然后:

template<Class C>
class Entity:public empty_if_false< C==Secondary, Entity<C> > {

有条件地拥有方法。

【讨论】:

  • 我能否指出,如果您在Cls 之前添加参数包,用户将永远无法为Cls 显式传递某些内容。
  • @StoryTeller 也许吧。首先,您不能将包强制为空。其次,规则背后的想法是模板应该能够进行早期检查,当代码永远不会有效时,允许生成错误,或者未来的标准修订版可以添加此类检查不会使旧的有效程序失效。您的技术可能会或可能不会遵守措辞;它违反精神。当然,模板类的模板方法使该规则模棱两可(是 1 个模板还是 2 个模板?)
  • 不确定它是 1 还是 2。但是,最新的标准草案似乎确实禁止它作为主要模板。所以我的立场是正确的。 eel.is/c++draft/temp.param#11虽然我怀疑有违精神,但是参数包的大小并不影响校验的有效性,
  • 不用等,我提供的报价并没有禁止函数模板。事实上,它明确表示“函数模板的模板形参包不应跟随另一个模板形参,除非 [...] 或具有默认参数”。所以我不仅没有违反标准的措辞,我还在遵循它:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
相关资源
最近更新 更多