代码之家  ›  专栏  ›  技术社区  ›  Jean-François Fabre

如何避免参数的隐式转换导致无限递归?

  •  2
  • Jean-François Fabre  · 技术社区  · 3 年前

    我有一个改编自的格式化方法 this example

    我已经将其简化为仅函数调用和打印

    当格式化字符串(第一个参数)是 const char *

    #include <stdio.h>
    #include <string>
    
    // base
    std::string format(const char *s)
    {
        printf("** %s\n",s);
        return "";
    }
    // recursive, should parse each argument and print the formatted string
    template<typename T, typename... Args>
    std::string format(const char *s, T value, Args... args)
    {
        printf("** %s\n",s);  // dummy
        return "";
    }
    
    int main()
    {
       format("foo");   
       printf("yay!\n");
    }
    

    现在我想通过一个 std::string format ,我必须做:

    std::string s = "foo";
    format(s.c_str());
    

    我想做

    format(s);
    

    所以我添加了这个

    // recursive
    template<typename... Args>
    std::string format(const std::string &s,Args... args)
    {
      return format(s.c_str(), args...);
    }
    

    但是当我直接传递字符串作为 std::字符串 它崩溃了。调试显示了无限递归。难以使用调试模板 std::字符串 结构,但我的猜测是

    return format(s.c_str(), args...);
    

    称自己为,因为 常量字符* 隐式转换为 std::字符串

    以下是完整的非工作示例:

    #include <stdio.h>
    #include <string>
    
    // recursive
    template<typename... Args>
    std::string format(const std::string &s,Args... args)
    {
      return format(s.c_str(), args...);
    }
    
    
    // base
    std::string format(const char *s)
    {
        printf("** %s\n",s);
        return "";
    }
    // recursive, should parse each argument and print the formatted string
    template<typename T, typename... Args>
    std::string format(const char *s, T value, Args... args)
    {
        printf("** %s\n",s);  // dummy
        return "";
    }
    
    int main()
    {
       std::string s = "foo";
       format(s);   
       printf("yay!\n");  // crashes before that
    }
    

    我可以放弃 常量字符* 版本完整 std::字符串 但我希望避免在传递字符串文字时构建字符串。

    那么如何保持传球能力 常量字符* 直接或 std::字符串 作为第一个论点?

    1 回复  |  直到 3 年前
        1
  •  1
  •   Fureeish    3 年前

    您的递归版本在其 return 陈述

    这是代码中最上面的声明和定义:

    template<typename... Args>
    std::string format(const std::string &s,Args... args)
    {
        return format(s.c_str(), args...);
    }
    

    它不会“看到”任何其他候选者,因此它总是递归地调用自己。

    你可以通过在上面的基本案例中引入声明来修复它。或者将所述案例移动到那里,包括它的实现:

    #include <stdio.h>
    #include <string>
    
    // base
    std::string format(const char *s)
    {
        printf("** %s\n",s);
        return "";
    }
    
    // recursive
    template<typename... Args>
    std::string format(const std::string &s,Args... args)
    {
        return format(s.c_str(), args...);
    }
    
    // recursive, should parse each argument and print the formatted string
    template<typename T, typename... Args>
    std::string format(const char *s, T value, Args... args)
    {
        printf("** %s\n",s);  // dummy
        return "";
    }
    
    int main()
    {
        std::string s = "foo";
        format(s);
        printf("yay!\n");  // crashes before that
    }
    

    输出:

    ** foo
    yay!