优雅的方法,以避免不依赖于模板类型的多个模板实例化的函数

Sku*_*del 3 c++ gcc templates c++11

我有一个基本类看起来像这样:

template <typename TCode, TCode SuccessVal>
class Error
{
public:
    typedef TCode code_t;

    Error(TCode code, char const *descr="Unknown Error."):
        code(code), descr(descr)
    {

    }

    ...

    char const *description() const
    {
        return descr;
    }

    ...

private:
    TCode code;
    char const *descr;
};
Run Code Online (Sandbox Code Playgroud)

它所做的就是封装某种错误代码枚举类,以便为日志记录提供更多的上下文.

现在说我有一个功能panic:

template <typename TCode, TCode SuccessVal>
void panic(Error<TCode, SuccessVal> const &e)
{
    puts("Panic!");
    printf("Unrecoverable error: %s", e.description());
    abort();
}
Run Code Online (Sandbox Code Playgroud)

使用-fdump-tree-original进行编译表明,在我的情况下,这会导致一些不同的函数,使用完全相同的代码.这是你所期望的,但可能不是你想要的.

一个显而易见的路径是一个只有消息和构造函数接收消息的基类,但我发现它相当缺乏吸引力.

我们从不使用错误代码本身,所以我们所做的一切都取决于T.我如何避免大量模板实例化编译成基本相同的代码?

另一个理想的特性是确保无论TCode是什么类型,它都可以对整数类型进行强制转换.

Ker*_* SB 6

这段代码的一个明显因素是:

[[noreturn]] void panic_with_message(char const * msg)
{
    std::printf("Panic!\nUnrecoverable error: %s\n", msg);
    std::fflush(stdout);
    std::abort();
}

template <typename T, T Val>
[[noreturn]] static inline void panic(Error<T, Val> e)
{
    panic_with_message(e.description());
}
Run Code Online (Sandbox Code Playgroud)

您只能将模板放入标题中,并附带函数声明,并将函数定义保存在单独的转换单元中.这应该使代码膨胀到最低限度:

// panic.hpp

#ifndef H_PANIC
#define H_PANIC

#include "error.hpp"  // for Error<T, Val>

[[noreturn]] void panic_with_message(char const * msg);

template <typename T, T Val>
[[noreturn]] static inline void panic(Error<T, Val> e)
{
    panic_with_message(e.description());
}

#endif
Run Code Online (Sandbox Code Playgroud)

  • 我承认通常对我的模板进行"<void>"特化并为此目的滥用它:( (3认同)
  • @ Cheersandhth.-Alf你确定g ++ 4.8.2不支持`[[noreturn]]`吗?至少在4.8.1中[编译](http://goo.gl/HZs6O8)这表明广义属性在4.8中实现:https://gcc.gnu.org/bugzilla/show_bug.cgi?id = 53528 (2认同)