需要一种方法,使仅标题库中的任何类型的模板常数

Need a way to have templated constants of any type in a header only library

本文关键字:标题 任何 类型 常数 方法 一种      更新时间:2023-10-16
goals:
1. store constants with their assignments in a header
2. keep constants in a namespace (without using #define)
3. allow constants to be whatever precision is needed for the app

我正在尝试将所有常数保留在同一名称空间中的Header库。我决定取消#define s并以正确的方式进行操作,例如使用:

namespace studio
{
    namespace constant
    {
        const char* WHITE_SPACE = "nrt ";
    }
}

希望这样的访问: studio::constant::WHITE_SPACE

这一切都很好,而且从我收集的东西来看,这样做为每个翻译单元创建其中一个,可能在链接过程中将其优化为一个实例。即使没有这样的优化,在这种情况下也可能还可以。

当我想在const char *以外添加其他类型的其他类型时,问题就会出现。例如,说我想允许浮动类型(双重或浮点)作为常数,但我想作为模板这样做,这样我就不必做这样的事情:

namespace studio
{
    namespace constant
    {
         const char* WHITE_SPACE = "nrt ";
         const float PI_FLOAT = 3.141592653589793;
         const double PI_DOUBLE = 3.141592653589793;
    }
}

所以我尝试使用模板类而不是名称空间,并带有静态函数,这些函数返回静态常数,例如:

namespace studio
{
    template <class FloatType = float>
    class constant
    {
    public:
        static const char* white_space_chars() {
            static const char* whiteSpaceChars = "nrt ";
            return whiteSpaceChars;
        }
        static const FloatType pi() {
            static const FloatType _pi = 3.141592653589793;
            return _pi;
        }
    }
}

然后将其访问:studio::constant<float>::pi()

,但是现在我有一个问题,如果我想要一个const char,即使它们与浮子无关,我必须提供模板参数,但必须像这样访问它们: studio::constant<float>::white_space_chars()因为 studio::constant::white_space_chars()即使我指定了一个默认的模板参数,显然不起作用,这显然仅适用于类。C 不允许在功能模板上默认。

所以现在我能看到的唯一方法是拥有studio :: constand_char,studio :: constant_float,studio :: constant_int等。这很荒谬,对吗?

我真正想要的就是在名称空间中定义我的定义...

您知道一种更好的方法来完成我要做的事情吗?可以在studio ::常数命名空间中使用不同类型的变量,而无需强迫库的用户为每个模板参数指定类型?最好不使用C 11向后兼容。

将模板移至实际使用的静态方法上:

namespace studio
{
    class constant
    {
    public:
        static const char* white_space_chars() {
            return "nrt ";
        }
        template <class FloatType = float>
        static const FloatType pi() {
            return FloatType(3.141592653589793);
        }
    };
}

然后您可以这样做:

float flt_pi = studio::constant::pi();
double dbl_pi = studio::constant::pi<double>();

我想这可以通过具有覆盖定义来完成:

#ifndef STUDIO_FLOAT_TYPE
typedef float STUDIO_FLOAT_TYPE;
#endif
namespace studio
{
    namespace constant
    {
         const char* WHITE_SPACE = "nrt ";
         const STUDIO_FLOAT_TYPE PI = 3.141592653589793;
    }
}

将允许用户在包含库标头之前覆盖浮点类型。至少只有一个定义,它仍然具有默认值。

因为肯定会在其他标题中使用这样的定义,所以我想将所有可自定义的定义在单个单独的库标题中所指的单个标题中定义可能很不错。

供将来参考,在C 14中,您可以做:

template <typename T>
const T PI = T(3.141592653589793);

请参阅变量模板。

作为一个例子:

// header.h
namespace constant
{
  template <typename T>
  constexpr T PI = T(3.141592653589793);
}
void foo();
// foo.cpp
#include <iostream>
#include "header.h"
void foo() {
    std::cout << constant::PI<int> << std::endl;
}
// main.cpp
#include <iostream>
#include "header.h"
int main()
{
  std::cout << constant::PI<float> << std::endl;
  foo();
}

这给出了输出:

3.14159
3