Home > Net >  c print current function input argument type, name, and value
c print current function input argument type, name, and value

Time:10-22

I am looking for a functionality that allows logging a function input arguments. For example:

void func(std::string& input_name, const int n){

     // print current function's inputs' type, name, and value
}

which after the function is called, the following will be printed or readable as string,

input1:
    type: std::string,
    name: input_name,
    value: "something",
input2:
    type: int,
    name: n,
    value: 12,

does anyone have a suggestion for such goal

------------edit

it is also ok for me if printing the type or name is not possible. I am flexible with a solution close to this, like if we can get a list of input arguments, or etc.

CodePudding user response:

This is a start using templates instead of macros : (Indeed with the added notion that typeid.name can output mangled names)

#include <iostream>
#include <string>
#include <sstream>

namespace details
{
    //-------------------------------------------------------------------------
    // formatters for parameters to functions
    //

    template<typename type_t>
    std::string format(const type_t& value)
    {
        std::ostringstream os;
        os << typeid(type_t).name() << ":";
        os << value;
        return os.str();
    }

    // output boolean as text
    std::string format(const bool& value)
    {
        return value ? std::string("bool:true") : std::string("bool:false");
    }

    // add quotes to string
    std::string format(const char* value)
    {
        std::ostringstream os;
        os << "const char*:\"";
        os << value;
        os << "\"";
        return os.str();
    }

    // recursively log all parameters
    template<typename arg_t, typename... args_t>
    inline void log_parameters(bool comma, const arg_t& arg, args_t... args)
    {
        if (comma) std::cout << ", ";
        std::cout << format(arg);

        if constexpr (sizeof...(args_t) > 0)
        {
            // true is print separating comma at next call
            log_parameters(true, std::forward<args_t>(args)...);
        }
    }

    //-------------------------------------------------------------------------

    template<typename... args_t>
    inline void log(const char* function, args_t... args)
    {
        std::cout << "function call to : " << function << "(";

        // if there are any arguments to log do so
        if constexpr (sizeof...(args_t) > 0)
        {
            // false == do not print a comma on first call
            log_parameters(false, std::forward<args_t>(args)...);
        }
        std::cout << ");\n";
    }
}

void my_function(const bool x, const int y, const char* str)
{
    details::log(__FUNCTION__, x, y, str);
}

int main()
{
    my_function(1, 42, "Hello world!");
}

CodePudding user response:

Printing a variable's type and value is fairly simple. But variable names don't exist at runtime, so the only way to obtain a variable's name as a string, without hard-coding it, is to use a macro at compile-time. Macros have a feature to stringify tokens.

Try something like this (sorry, this is from memory, I can't get to a compiler at the moment, I'll update this later today):

#include <iomanip>
#include <typeinfo>
#include <type_traits>

template <typename T>
std::string getTypeName()
{
    // TODO: to get a more human-readable output, use
    // if-constexpr, or template specialization, or one
    // of the solutions from https://stackoverflow.com/q/281818/65863... 
    return typeid(T).name();
} 

template<typename T>
std::string stringify(T&& param)
{
    std::ostringstream oss;
    if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, char*> || std::is_same_v<T, const char*>)
        oss << std::quoted(param);
    else
        oss << param;
    return oss.str();
}

#define LOG(num, param) \
    std::cout << "input" << num << ":" << std::endl \
    std::cout << "\ttype: " << getTypeName<decltype(param)>() << "," << std::endl \
    std::cout << "\tname: " << #param << "," << std::endl \
    std::cout << "\tvalue: " << stringify(param) << "," << std::endl;

void func(std::string& input_name, const int n){
    LOG(1, input_name)
    LOG(2, n)
}
  • Related