【问题标题】:Variadic templates and variadic functions combination可变参数模板和可变参数函数组合
【发布时间】:2017-09-19 12:13:28
【问题描述】:

我正在创建一个日志记录函数,它一方面需要能够解析任意数量的参数,但另一方面将始终使用 __func__ 和 this(调用对象)。

如果我只使用这样的可变参数模板

template<typename... Args>
void
log_device_message_template(const class *object, 
               char const *func,
               char const *const format,
               Args const &... args)noexcept
{
 log(format, to_str(object).c_str(),format, to_str(args).c_str()...);
}

我必须像这样打电话给log_device_message_templatelog_device_message_template(this,__func__,some format,some parameters)

所以我添加了宏:

#define log_api_call(format, ...)                                                                                                                                                         \
    log_device_message_template(                                                                                                   \
        this, __func__, "%s::%s(" format ")", ##__VA_ARGS__)

问题是我遇到了段错误,可能是由于某处的格式错误。由于使用了可变参数模板,添加 __attribiute__(format) 不起作用...

这是测试记录器的 python 测试的错误:

lookup in file=***** [0]
     28371: symbol=_ZN5***6logger27log_device_message_templateIINS_14*****E13****EEEvNS_21logger_component_eENS_17logger_level_eEPKcPKNS_9objectES7_DpRT_;  lookup in file=**** [0]
     28371: ****: error: symbol lookup error: undefined symbol: _ZN5***6logger27log_device_message_templateIINS_14****E13****EEEvNS_21logger_component_eENS_17logger_level_eEPKcPKNS_9objectES7_DpRT_ (fatal)

【问题讨论】:

  • 可能是打错了,但你搞乱了宏中参数的顺序。
  • 符号查找错误不是段错误。您似乎正在尝试调用尚未编译的 log_device_message_template 的实例化。为什么实例化不存在是任何人的猜测。我们可能需要查看包装它的 Python 库的详细信息。

标签: c++ variadic-templates variadic-macros


【解决方案1】:

这是另一种处理它的方法,它巧妙地避免了宏。

注意,在这种情况下,我将日志记录发送到标准输出,但这很容易改变。我还使用std::ostringstream 来构建日志消息。它并不以性能着称,因此非常适合作为自定义点。

但是,如果您喜欢这种方法,这应该可以帮助您入门:

#include <iostream>
#include <sstream>
#include <tuple>
#include <utility>

// define a constant index type
template<std::size_t N> using index_c = std::integral_constant<std::size_t, N>;

// emitting an item at index 0 has no prefix    
template<class T>
void emit_item(std::ostream &os, index_c<0>, T const &t)
{
    os << t;
}


// emitting an item at index N (!= 0) has a comma prefix
template<std::size_t N, class T>
void emit_item(std::ostream &os, index_c<N>, T const &t)
{
    os << ", " << t;
}

// emit args 0 .. N-1
template<class Tuple, std::size_t...Is>
void emit_arglist(std::ostream &sink, Tuple &&tuple, std::index_sequence<Is...>)
{
    using expand = int[];
    void(expand{0,
                (emit_item(sink, index_c<Is>(), std::get<Is>(tuple)), 0)...
    });

};

// emitting a 'more' at index 0 has a prefix
template<class T>
void emit_more(std::ostream &os, index_c<0>, T const &t)
{
    os << " : " << t;
}

// emitting a 'more' at index N (!= 0) has a space prefix
template<std::size_t N, class T>
void emit_more(std::ostream &os, index_c<N>, T const &t)
{
    os << " " << t;
}

template<class Tuple, std::size_t...Is>
void emit_more(std::ostream &sink, Tuple &&tuple, std::index_sequence<Is...>)
{
    using expand = int[];
    void(expand{0,
                (emit_more(sink, index_c<Is>(), std::get<Is>(tuple)), 0)...
    });

};

template<typename... Args, typename ...MoreStuff>
std::string
make_log_string(const char *object,
                char const *func,
                std::tuple<Args const &...> const& args,
               MoreStuff&&...morestuff) noexcept
{
    std::ostringstream ss;
    ss << object << "::" << func << '(';
    emit_arglist(ss, args, std::make_index_sequence<sizeof...(Args)>());
    ss << ')';
    emit_more(ss, std::tie(morestuff...), std::make_index_sequence<sizeof...(MoreStuff)>());
    return ss.str();
}

// syntactic sugar for indicating arguments    
template<class...Arg>
decltype(auto) args(Arg const&...args)
{
    return std::tie(args...);
}


int main()
{
    int a = 0, b = 1, c = 2;
    std::string sa = "xxx", sb = "yyy", sc = "zzz";

    const char* Class = "foo";
    const char* Func = "var";

    std::cout << make_log_string(Class, Func, args(a, b, c)) << std::endl;
    std::cout << make_log_string(Class, Func, args(sa, b, sc)) << std::endl;
    std::cout << make_log_string(Class, Func, args(sa, b, sc), "more stuff") << std::endl;
    std::cout << make_log_string(Class, Func, args(), "empty", "argument", "list") << std::endl;

}

预期输出:

foo::var(0, 1, 2)
foo::var(xxx, 1, zzz)
foo::var(xxx, 1, zzz) : more stuff
foo::var() : empty argument list

加上更多样板,我们可以这样写:

std::cout << make_log_string(method(Class, Func)(a, b, c)) << std::endl;
std::cout << make_log_string(method(Class, Func)(sa, b, sc)) << std::endl;
std::cout << make_log_string(method(Class, Func)(sa, b, sc), "more stuff") << std::endl;
std::cout << make_log_string(method(Class, Func)(), "empty", "argument", "list") << std::endl;

这里是:

#include <iostream>
#include <sstream>
#include <tuple>
#include <utility>

template<std::size_t N> using index_c = std::integral_constant<std::size_t, N>;

template<class T>
void emit_item(std::ostream &os, index_c<0>, T const &t)
{
    os << t;
}

template<std::size_t N, class T>
void emit_item(std::ostream &os, index_c<N>, T const &t)
{
    os << ", " << t;
}

template<class Tuple, std::size_t...Is>
void emit_arglist(std::ostream &sink, Tuple &&tuple, std::index_sequence<Is...>)
{
    using expand = int[];
    void(expand{0,
                (emit_item(sink, index_c<Is>(), std::get<Is>(tuple)), 0)...
    });

};

template<class T>
void emit_more(std::ostream &os, index_c<0>, T const &t)
{
    os << " : " << t;
}

template<std::size_t N, class T>
void emit_more(std::ostream &os, index_c<N>, T const &t)
{
    os << " " << t;
}

template<class Tuple, std::size_t...Is>
void emit_more(std::ostream &sink, Tuple &&tuple, std::index_sequence<Is...>)
{
    using expand = int[];
    void(expand{0,
                (emit_more(sink, index_c<Is>(), std::get<Is>(tuple)), 0)...
    });

};

template<class...Args>
struct method_with_args;

struct method
{
    constexpr method(const char* c, const char* f) : klass(c), func(f) {}
    const char* klass;
    const char* func;

    template<class...Args>
    auto operator()(Args const&...args) -> method_with_args<Args...>;

    friend std::ostream& operator<<(std::ostream& os, const method& m)
    {
        return os << m.klass << "::" << m.func;
    }
};

template<class...Args>
struct method_with_args
{
    friend std::ostream& operator<<(std::ostream& os, method_with_args const& ma)
    {
        os << ma.m << '(';
        emit_arglist(os, ma.args, std::make_index_sequence<sizeof...(Args)>());
        return os << ')';
    }

    method m;
    std::tuple<Args const&...> args;
};

template<class...Args>
auto method::operator()(Args const&...args) -> method_with_args<Args...>
{
    return method_with_args<Args...>{*this, std::tie(args...)};

}

struct function
{
    const char* name;
};

template<typename Method, typename ...MoreStuff>
std::string
make_log_string(Method m,
                MoreStuff &&...morestuff) noexcept
{
    std::ostringstream ss;
    ss << m;
    emit_more(ss, std::tie(morestuff...), std::make_index_sequence<sizeof...(MoreStuff)>());
    return ss.str();
}


int main()
{
    int a = 0, b = 1, c = 2;
    std::string sa = "xxx", sb = "yyy", sc = "zzz";

    const char *Class = "foo";
    const char *Func = "var";

    std::cout << make_log_string(method(Class, Func)(a, b, c)) << std::endl;
    std::cout << make_log_string(method(Class, Func)(sa, b, sc)) << std::endl;
    std::cout << make_log_string(method(Class, Func)(sa, b, sc), "more stuff") << std::endl;
    std::cout << make_log_string(method(Class, Func)(), "empty", "argument", "list") << std::endl;
}

【讨论】:

    猜你喜欢
    • 2015-07-07
    • 2011-11-24
    • 2016-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-20
    • 1970-01-01
    相关资源
    最近更新 更多