【问题标题】:Function parameter that could be either char*, long or int. Is it possible?可以是 char*、long 或 int 的函数参数。可能吗?
【发布时间】:2017-09-25 19:00:57
【问题描述】:

我正在编写一些逻辑来做一些日志记录,有一堆 C++ 与 C 混合,因为这个库的大部分内容都是为了 p/Invoked。我已经设法编写了一个记录消息和可选参数的函数:

void writeToLog(char* message, char* arg) {
    std::ofstream file;
    file.open(fullpath, std::ios::in | std::ios::app);
    if (file.is_open()) {
        std::string fullMessage = getCurrentDateTime();
        fullMessage.append(message);
        if (arg != 0)
            fullMessage.append(arg);
        fullMessage.append("\n");
        const char* pcMessage = fullMessage.c_str();
        file << pcMessage;
        std::cout << pcMessage;
    }
    file.close();
}

但是它只需要 char* 作为 args,但我想将它们与 int 和 long 一起使用......我已经尝试过:

void writeToLog(char* message, void* arg) {
    std::ofstream file;
    file.open(fullpath, std::ios::in | std::ios::app);
    if (file.is_open()) {
        std::string fullMessage = getCurrentDateTime();
        fullMessage.append(message);
        if (arg != 0)
            fullMessage.append((char*)&arg);
        fullMessage.append("\n");
        const char* pcMessage = fullMessage.c_str();
        file << pcMessage;
        std::cout << pcMessage;
    }
    file.close();
}

但无论数据类型如何,它都会打印/写入乱码。请指出您认为合适的任何其他错误,我在 C/C++ 方面有点菜鸟。

【问题讨论】:

  • 使用模板。这就是他们的目的。
  • 就像我说的,我是一个 C++ 菜鸟,我不知道模板是如何工作的,但我会看看
  • 听起来你可以使用 good C++ book 然后
  • How to write a template?的可能重复
  • @NathanOliver 如果该函数是 P/Invoke 的,那么模板实际上并不是一个好的答案。它们只能由 C++ 代码实例化,没有包装器就无法从 C# 调用它们。

标签: c++ casting void-pointers


【解决方案1】:

有两种方法可以解决这个问题。第一种方法是重载函数。这意味着您将一遍又一遍地编写相同的函数,除了使用不同的类型作为参数。 示例

#include <iostream>
using namespace std;

class printData {
public:
  void print(int i) {
     cout << "Printing int: " << i << endl;
  }

  void print(double  f) {
     cout << "Printing float: " << f << endl;
  }

  void print(char* c) {
     cout << "Printing character: " << c << endl;
  }
};

int main(void) {
 printData pd;

 // Call print to print integer
 pd.print(5);

 // Call print to print float
 pd.print(500.263);

 // Call print to print character
 pd.print("Hello C++");

 return 0;
}

此代码打印:

Printing int: 5
Printing float: 500.263
Printing character: Hello C++

第二个选项是使用模板。基本上,你会这样做

template<class T>
void writeToLog(char* message, T arg){
   //continue to write code here without assuming anything about the type of arg
}

重载函数链接:https://www.tutorialspoint.com/cplusplus/cpp_overloading.htm

模板链接:http://www.cplusplus.com/doc/oldtutorial/templates/

【讨论】:

【解决方案2】:

我的建议:

  1. 将函数更改为函数模板。
  2. 使用标准库函数std::to_string 将数字转换为std::string。添加一些包装器代码,以便您可以使用相同的函数调用来处理char*char const*
  3. 使用包装函数的返回值附加到正在写入的消息。
  4. 删除对std::string::c_str() 的呼叫。 std::string 可以写入文件,std::cout
  5. 无需致电file.close();。函数返回时会关闭。

namespace my_app
{
   template <typename T>
   std::string toString(T in)
   {
      return std::to_string(in);
   }

   std::string toString(char const* in)
   {
      return std::string(in);
   }

   std::string toString(std::string const& in)
   {
      return in;
   }
}

template <typename T>
void writeToLog(char* message, T arg) {
   std::ofstream file;
   file.open(fullpath, std::ios::in | std::ios::app);
   if (file.is_open()) {
      std::string fullMessage = getCurrentDateTime();
      fullMessage.append(message);
      fullMessage.append(my_app::toString(arg));
      fullMessage.append("\n");
      file << fullMessage;
      std::cout << fullMessage;
   }
}

// Overload to deal with the optional parameter
void writeToLog(char* message) {
   writeToLog(message, "");
}

【讨论】:

  • 奇怪的是,如果我从fullMessage 中删除.c_str(),我会收到编译器错误:Error C2679 binary '&lt;&lt;' : no operator found which takes a right-hand operand of type 'std::string' (or there is no acceptable conversion)
  • @S.O.,这很奇怪。你用的是什么编译器?
【解决方案3】:

您可以使用模板。

这是一个简单的示例,向您展示了基本思想。 (虽然没有测试)

template <typename T, typename U>
void func(T param1, U param2)
{
    std::cout << param1 << param2;
}

以 main 为例:

func("A", 5);

func (2, 2.5);

您需要阅读一些内容才能满足您的需要。

【讨论】:

    【解决方案4】:

    任何托管的object 都可以编组为VARIANT。当然,如果这样做,编译器不会进行任何类型检查。

    // C# P/Invoke
    static extern void writeToLog(string message, ref object arg);
    
    // C++
    void writeToLog(const char* message, const VARIANT* arg) {
        std::ofstream file;
        file.open(fullpath, std::ios::in | std::ios::app);
        if (file.is_open()) {
            std::string fullMessage = getCurrentDateTime();
            fullMessage.append(message);
            if (arg) {
                switch (V_VT(arg)) {
                    case VT_I4:
                        message.append(V_I4(arg));
                        break;
                    case VT_I8:
                        message.append(V_I8(arg));
                        break;
                    case VT_BSTR:
                        message.append(V_BSTR(arg));
                        break;
                }
            }
            fullMessage.append("\n");
            const char* pcMessage = fullMessage.c_str();
            file << pcMessage;
            std::cout << pcMessage;
        }
        file.close();
    }
    

    【讨论】:

    • 你的看起来是迄今为止最好的。我本来打算使用模板,但让我先试试你的。
    • @S.O.如果您主要通过 C++(而不是 P/Invoke)调用,那么实际上我的调用会更加困难。
    • 是的,我刚刚意识到,我没有意识到你准备好它被 P/Invoked。我会尝试模板,但做得很好!
    猜你喜欢
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    相关资源
    最近更新 更多