jjzjj

c++ - 无限递归 `enable_if`

coder 2024-02-03 原文

在尝试为另一种类型 T 编写 wrapper 类型时,我遇到了一个相当令人讨厌的问题:我想定义一些二元运算符(例如 +) 将 wrapper 上的任何操作转发给底层类型,但我需要这些运算符接受任何涉及 wrapper 的潜在组合:

wrapper() + wrapper()
wrapper() + T()
T()       + wrapper()

天真的方法涉及直接编写所有潜在的重载。

但我不喜欢编写重复的代码并且想要更多的挑战,所以我选择使用一个非常通用的模板来实现它并使用 enable_if 限制潜在的类型。

我的尝试显示在问题的底部(抱歉,这是我能想到的最小值)。问题是它会遇到无限递归错误:

  1. 为了评估 test() + test(),编译会查看所有潜在的重载。
  2. 此处定义的运算符实际上是一个潜在的重载,因此它尝试构造返回类型。
  3. 返回类型有一个 enable_if 子句,它应该防止它成为一个有效的重载,但编译器只是忽略它并尝试首先计算 decltype , 这需要 ...
  4. ... operator+(test, test) 的实例化。

我们又回到了起点。 GCC 非常好,可以吐出一个错误; Clang 只是段错误。

什么是好的、干净的解决方案? (请记住,还有其他运算符需要遵循相同的模式。)

template<class T>
struct wrapper { T t; };

// Checks if the type is instantiated from the wrapper
template<class>   struct is_wrapper              : false_type {};
template<class T> struct is_wrapper<wrapper<T> > : true_type  {};

// Returns the underlying object
template<class T> const T& base(const T& t)          { return   t; }
template<class T> const T& base(const wrapper<T>& w) { return w.t; }

// Operator
template<class W, class X>
typename enable_if<
    is_wrapper<W>::value || is_wrapper<X>::value,
    decltype(base(declval<W>()) + base(declval<X>()))
>::type operator+(const W& i, const X& j);

// Test case
struct test {};
int main() {
    test() + test();
    return 0;
}

这是一个相当笨拙的解决方案,除非必须,否则我宁愿不使用它:

// Force the evaluation to occur as a 2-step process
template<class W, class X, class = void>
struct plus_ret;
template<class W, class X>
struct plus_ret<W, X, typename enable_if<
    is_wrapper<W>::value || is_wrapper<X>::value>::type> {
    typedef decltype(base(declval<W>()) + base(declval<X>())) type;
};

// Operator
template<class W, class X>
typename plus_ret<W, X>::type operator+(const W& i, const X& j);

最佳答案

作为对 TemplateRex 注释的补充,我建议使用宏来实现所有重载并将运算符作为参数:

template<class T>
struct wrapper { T t; };

#define BINARY_OPERATOR(op)                                      \
  template<class T>                                              \
  T operator op (wrapper<T> const& lhs, wrapper<T> const& rhs);  \
  template<class T>                                              \
  T operator op (wrapper<T> const& lhs, T const& rhs);           \
  template<class T>                                              \
  T operator op (T const& lhs, wrapper<T> const& rhs); 

BINARY_OPERATOR(+)
BINARY_OPERATOR(-)

#undef BINARY_OPERATOR

// Test case
struct test {};
test operator+(test const&, test const&);
test operator-(test const&, test const&);

int main() {
    test() + test();
    wrapper<test>() + test();
    test() - wrapper<test>();
    return 0;
}

关于c++ - 无限递归 `enable_if`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18072792/

有关c++ - 无限递归 `enable_if`的更多相关文章

  1. ruby - 树顶语法无限循环 - 2

    我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  4. ruby - ruby 中有 each_if 吗? - 2

    假设我在Ruby中有这个each循环。@list.each{|i|putsiifi>10breakend}我想循环遍历列表直到满足条件。这让我感到“不像Ruby”,因为我是Ruby的新手,是否有Ruby方法可以做到这一点? 最佳答案 您可以使用Enumerable#detect或Enumerable#take_while,取决于您想要的结果。@list.detect{|i|putsii>10}#Returnsthefirstelementgreaterthan10,ornil.正如其他人所指出的,更好的风格是先进行子选择,然后再对其

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby-on-rails - rails : check if the model was really saved in after_save - 2

    ActiveRecord用于在每次调用保存方法时调用after_save回调,即使模型没有更改并且没有生成插入/更新查询也是如此。这实际上是默认行为。在大多数情况下这没问题。但是一些after_save回调对模型是否实际保存的事情很敏感。有没有办法确定模型是否实际保存在after_save中?我正在运行以下测试代码:classStage 最佳答案 ActiveRecordusetocallafter_savecallbackeachtimesavemethodiscalledevenifthemodelwasnotchangedan

  8. ruby - 你会如何在 Ruby 中表达成语 "with this object, if it exists, do this"? - 2

    在Ruby(尤其是Rails)中,您经常需要检查某物是否存在,然后对其执行操作,例如:if@objects.any?puts"Wehavetheseobjects:"@objects.each{|o|puts"hello:#{o}"end这是最短的,一切都很好,但是如果你有@objects.some_association.something.hit_database.process而不是@objects呢?我将不得不在if表达式中重复两次,如果我不知道实现细节并且方法调用很昂贵怎么办?显而易见的选择是创建一个变量,然后测试它,然后处理它,但是你必须想出一个变量名(呃),它也会在内存中

  9. ruby - 在 Ruby 的 if 语句中检查 bash 命令 - 2

    如何在Ruby的if语句中检查bash命令的返回值(true/false)。我想要这样的东西,if("/usr/bin/fswscell>/dev/null2>&1")has_afs="true"elsehas_afs="false"end它会提示以下错误含义,它总是返回true。(irb):5:warning:stringliteralincondition正确的语法是什么?更新:/usr/bin/fswscell寻找afs安装和运行状态。它会抛出这样的字符串,Thisworkstationbelongstocell如果afs没有运行,命令以状态1退出 最

  10. ruby - 变量赋值后的 if 语句 - 有多常见? - 2

    我最近与一位同事讨论了以下Ruby语法:value=ifa==0"foo"elsifa>42"bar"else"fizz"end我个人并没有看到太多这种逻辑,但我的同事指出,这实际上是一种相当普遍的Rubyism。我试着用谷歌搜索这个主题,但没有找到任何文章、页面或SO问题来讨论它,这让我相信这可能是一种非常实际的技术。然而,另一位同事发现语法令人困惑,而是将上面的逻辑写成这样:ifa==0value="foo"elsifa>42value="bar"elsevalue="fizz"end缺点是value=的重复声明和隐式elsenil的丢失,如果我们想使用它的话。这也感觉它与Ruby

随机推荐