c ++模板自动参数

时间:2015-09-02 14:57:39

标签: c++ templates c++11

我正在尝试编写一个日志记录例程(几乎)自动跟踪进入和退出方法。类似的东西:

int rc=0;
LOG_ENTRY("MyFunction()", rc);

LOG_ENTRY是一个定义本地对象的宏。创建对象后,它将使用" Entry MyFunction()"来调用记录器。当在跟踪方法结束时销毁对象时,析构函数将发出"退出MyFunction()返回0"其中0是退出时rc的值。

现在我的大部分工作都使用c ++,除了必须为每种类型的返回值定义日志对象的类的构造函数:

class IM_EX_CTIBASE LogEntry
{
    Log *logger;
    const char* func;
    void *rc;
public:
    LogEntry(Log *logger, const char* func, int *rc)
    {
        this->logger=logger;
        this->func=func;
        this->rc=rc;
        logger->log("Entry " << func);
    }
    ~LogEntry()
    {
        logger->log("Exit " << func << *rc);
    }
}

(请原谅任何拼写错误,这是实际代码的简化版本。)

现在我希望将其重写为模板,其中rc类型可以在外部定义。我认为auto是在构造函数上定义rc的极好可能性,但是auto在那里不起作用。

由于编译器已经知道类型是什么,为什么我需要在这里定义它。 log()(接受流)应该已经知道如何使用rc。

我看过许多替代品,但似乎没有什么是我想要的。有人建议&#34;像make_pair那样做#34;但是在深入研究之后它似乎创建了一个我认为你不能在构造函数中使用的函数模板。

有人有什么想法吗?

2 个答案:

答案 0 :(得分:3)

这些方面的一些东西,也许是:

template <typename T>
class LogEntry {
public:
  LogEntry(Log *logger, const char* func, T* rc);
};

#define LOG_ENTRY(name, ret) \
LogEntry<decltype(ret)> log_entry(logger, name, &ret);

填写LogEntry实施细节仍然是读者的练习。

答案 1 :(得分:0)

我打算给你贴一个我在项目中使用的个人日志记录系统,但它与系统和Qt的关系非常糟糕。 Igor的答案看起来不错,我想补充说你可以使用(我认为可能是g ++特定的)__FUNC __(或__PRETTY_FUNCTION__)宏来避免每次都输入函数名。另一种可能性是定义一个RETURN宏,它使用SFINAE来检测返回类型是否可以流式传输到cout / cerr,如果是,则执行此操作然后从函数中返回值。这可以这样做:

#ifdef SUPPORTS_CPP_11

template<class T> struct ValuetoString{ //SFINAE class to check if a value type can be converted implicitly to
    // a printable string, and if so, print() returns a string for a value of type T
    typedef char Yes; 
    typedef struct{ char a[2]; } OStream;

    template<typename J> static OStream Test( //For types that output to std::ostream
        typename UnReference<decltype(std::declval<std::ostream&>() << std::declval<J>())>::Type *param);

    template<typename J> static UnPrintable Test(...); //Always prever above if it be well-formed.

    template<bool ostream, class Dummy> struct print;
    template<class Dummy> struct print<true, Dummy>{
        static inline std::string ret(T Value){
            std::ostringstream a;  a << Value; return a.str(); }
    };
    template<class Dummy> struct print<false, Dummy>{
        static inline std::string ret(const T &Value) {
            return std::string(BasicTypeName(T) + " is an unprintable type"); }
    };
    static inline std::string Print(const T &Value){
        return print<(sizeof(Test<T>(NULL, NULL)) == sizeof(OStream)), int>::ret(Value); }
};

template<typename T> inline std::string FriendlyInspect(T val, const char *name){
    return std::string(FriendlyTypeName(val, name) + " with value " + ValuetoString<T>::print(val) );
}
template<typename T> inline std::string FriendlyInspect(T* val, const char *name){
    return std::string(FriendlyTypeName(val, name) + " with value " + ValuetoString<T>::print(val) );
}

#else
template<typename T> struct ValuetoString{
    static std::string Print(T Value) {return std::string() += FriendlyTypeName<T>(Value,"") += " is an unprintable type";}
};
#endif //SUPPORTS_CPP11

例如,如果你调用FriendlyInspect(9),它将输出typename,'int'和值'9',但是如果你调用FriendlyInspect(MyObjectThatCantBeStreamed),它将不会产生编译时错误但是而只是打印类型名称。 我从原版修改了它,我不知道是否还需要Dummy,但它没有任何伤害。在这种情况下,FriendlyTypeName使用一个g ++函数,其名称我不记得在g ++或其他平台上解析type_info :: name()只是不管它,UnReference只是从类型中删除引用。