【问题标题】:Define function / method if not defined before c++如果在 c++ 之前未定义,则定义函数/方法
【发布时间】:2017-01-11 10:17:48
【问题描述】:

我还没有使用C++11,所以我自己写了函数to_string(whatever)。仅当它们不存在时才应编译它们。如果我切换到 C++11,它们应该被跳过。我有这样的事情:

#ifndef to_string

string to_string(int a){
    string ret;
    stringstream b;
    b << a;
    b >> ret;
    return ret;
}

string to_string(double a){
    string ret;
    stringstream b;
    b << a;
    b >> ret;
    return ret;
}

#endif

这显然不起作用。这样的事情可能吗?如果可以,怎么做?

【问题讨论】:

  • 它在 C++11 之前工作,见 cpp.sh/86ldr
  • @ArnavBorborah 好吧,它不应该工作。 std::to_string 是 C++11 的东西
  • 我个人认为这是一个非常糟糕的做法,这个问题也没有很好的答案。 C++ 标准不提供to_string,而是提供std::to_string,这是非常不同的。这意味着,如果您的标准不支持,则不能使用 std::to_string。现在再想一想 - 假设您已经使用 C++11。现在怎么办?如果您使用已接受答案中的宏,您会在余生中使用它而不是std::to_string吗?非常非常糟糕的主意。
  • 它不起作用的原因是#ifdef 只测试预处理器 定义的存在,而不是像std::to_string 这样的常规函数​​。这就是#ifdef 可以测试的全部内容,因为预处理器指令由 ... 预处理器执行。

标签: c++ function c++11 methods precompile


【解决方案1】:

这是namespace存在的主要目的之一。

我的建议是将您的个人功能包含在适当的命名空间中,例如:

namespace myns {
  std::string to_string(...) {
    // ...
  }
  // etc...
}

这是避免未来冲突问题的基础。

之后,当您要使用该功能时,您可以通过 MACRO 替换简单地选择合适的功能。

类似:

#if (__cplusplus >= 201103L) 
  #define my_tostring(X) std::to_string(X)
#else
  #define my_tostring(X) myns::to_string(X)
#endif

注意__cplusplus 是一个pre-defined macro,其中包含有关标准版本的编译信息。


编辑:
不那么“暴力”的东西,它将根据标准版本为该特定功能选择适当的命名空间:

#if (__cplusplus >= 201103L) 
  using std::to_string;
#else
  using myns::to_string;
#endif

// ... somewhere
to_string(/*...*/);  // it should use the proper namespace

【讨论】:

  • #if (__cplusplus &gt;= 201103L) 是我需要的。谢谢大哥。
  • 不是#define宏,而是在#ifdef块的每个分支中放置一个适当的using ns::to_string。减少对编译器名称空间的暴力。
【解决方案2】:

您无法测试它们是否被定义为这样,但您可以检查语言版本:

#if __cplusplus < 201103L

(有一个有用的预定义编译器宏集合here。)

【讨论】:

    【解决方案3】:

    您可以使用 SFINAE,记住非模板重载优于模板重载。这在 pre-c++11 和 c++11 中都可以编译:

    #include <sstream>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    namespace my {
       template <bool V, class T>
       struct enable_if {
       };
    
       template <class T>
       struct enable_if<true, T> {
          typedef T type;
       };
    
       template <class T1, class T2>
       struct is_same {
          static const bool value = false;
       };
    
       template <class T>
       struct is_same<T, T> {
          static const bool value = true;
       };
    }
    
    template <class T>
    typename my::enable_if<my::is_same<T, int>::value
                          || my::is_same<T, double>::value, string>::type
      to_string(T const& a) {
        string ret;
        stringstream b;
        b << a;
        b >> ret;
        return ret;
    }
    
    int main() {
       cout << to_string(2) << endl;
       cout << to_string(3.4) << endl;
    }
    

    【讨论】:

      【解决方案4】:

      您可以将函数放在宏中,如下所示:

      #ifndef to_string
      #define to_string
      
      //....
      
      #endif
      

      然后,在另一个文件中,这样写:

      #if __cplusplus >= 201103L
          #undef to_string
      #else
          #define to_string
      #endif
      

      【讨论】:

      • 代码不需要检查是否定义了to_string#undef 可以与尚未定义的名称一起使用。
      【解决方案5】:

      Boost.Config 有一些macros 来检查是否支持/使用了 C++11 功能。

      【讨论】:

      • 我在这个列表中没有看到 to_string 函数的宏。
      猜你喜欢
      • 2023-02-05
      • 2021-10-16
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2017-12-28
      • 1970-01-01
      • 2019-09-14
      • 2021-04-07
      相关资源
      最近更新 更多