C++ 编译时常量id

C++ 编译时常量id,c++,templates,template-meta-programming,C++,Templates,Template Meta Programming,鉴于以下情况: template<typename T> class A { public: static const unsigned int ID = ?; }; 模板 甲级 { 公众: 静态常量无符号整数ID=?; }; 我希望ID为每个T生成一个唯一的编译时ID。我考虑过\uuuuu COUNTER\uuuu和boost PP库,但到目前为止都没有成功。我怎样才能做到这一点 Edit:ID必须在switch语句中可用 Edit2:基于静态方法或成员地址的所有答案都

鉴于以下情况:

template<typename T>
class A
{
public:
    static const unsigned int ID = ?;
};
模板
甲级
{
公众:
静态常量无符号整数ID=?;
};
我希望ID为每个T生成一个唯一的编译时ID。我考虑过
\uuuuu COUNTER\uuuu
和boost PP库,但到目前为止都没有成功。我怎样才能做到这一点

Edit:ID必须在switch语句中可用


Edit2:基于静态方法或成员地址的所有答案都不正确。尽管它们确实创建了一个唯一的ID,但它们在编译时无法解析,因此不能用作switch语句的实例。

使用静态函数的内存地址

template<typename T>
class A  {
public:
    static void ID() {}
}; 
模板
甲级{
公众:
静态void(){}
}; 

(&(A::ID))
将不同于
(&(A::ID))
等等。

假设一个符合标准的编译器(关于一个定义规则):

模板
甲级
{
公众:
静态字符ID_存储;
静态常量无效*常量ID;
};
模板字符A::ID\u存储;
模板常量void*常量A::ID=&A::ID\u存储;
<> P>从C++标准3.2.5定义规则[Basic .DEF.ODR](粗体强调地雷):

。。。如果D是一个模板,并且在多个翻译中定义 则上述清单中的最后四项要求应适用 从模板中使用的模板的封闭范围中删除名称 定义(14.6.3),以及 实例化(14.6.2)如果D的定义满足所有这些条件 要求,则程序的行为应与单个 D的定义。如果D的定义不满足这些要求 需求,则行为未定义


如果可接受非单调值和
intptr\t

template<typename T>
struct TypeID
{
private:
    static char id_ref;
public:
    static const intptr_t ID;
};

template<typename T>
  char TypeID<T>::id_ref;
template<typename T>
  const intptr_t TypeID<T>::ID = (intptr_t)&TypeID<T>::id_ref;
模板
结构类型ID
{
私人:
静态字符id_ref;
公众:
静态常量intptr\t ID;
};
模板
字符类型id::id\u ref;
模板
常量intptr\u t TypeID::ID=(intptr\u t)和TypeID::ID\u ref;
如果必须有int,或者必须有单调递增的值,我认为使用静态构造函数是唯一的方法:

// put this in a namespace
extern int counter;

template<typename T>
class Counter {
private:
  Counter() {
    ID_val = counter++;
  }
  static Counter init;
  static int ID_val;
public:
  static const int &ID;
};

template<typename T>
  Counter<T> Counter<T>::init;
template<typename T>
  int Counter<T>::ID_val;
template<typename T>
  const int &Counter<T>::ID = Counter<T>::ID_val;

// in a non-header file somewhere
int counter;
//将其放入命名空间中
外部内部计数器;
模板
班级计数器{
私人:
计数器(){
ID_val=计数器++;
}
静态计数器初始化;
静态int-ID_-val;
公众:
静态常量int&ID;
};
模板
计数器:init;
模板
int计数器::ID_val;
模板
常量int&Counter::ID=Counter::ID\u val;
//在某个非头文件中
整数计数器;

请注意,如果在共享库和应用程序之间共享这些技术,则这两种技术都不安全

这是办不到的。静态对象的地址是最接近唯一id的地址,但是为了获取此类对象的地址(甚至静态常量积分),必须在某个地方定义它们。根据“一个定义”规则,它们应该在CPP文件中定义,这是无法完成的,因为它们是模板。如果您在头文件中定义静态,那么每个编译单元都将在不同的地址实现它自己的版本。

这对我来说似乎没问题:

template<typename T>
class Counted
{
  public:
  static int id()
  {
    static int v;
    return (int)&v;
  }
};

#include <iostream>

int main()
{
  std::cout<<"Counted<int>::id()="<<Counted<int>::id()<<std::endl;
  std::cout<<"Counted<char>::id()="<<Counted<char>::id()<<std::endl;

}
模板
班级人数
{
公众:
静态int-id()
{
静态int-v;
返回(int)和v;
}
};
#包括
int main()
{

我最近遇到了这个问题。 我的解决方案:

counter.hpp

class counter
{
    static int i;
    static nexti()
    {
        return i++;
    }
};
Counter.cpp:

int counter::i = 0;
templateclass.hpp

#include "counter.hpp"

    template <class T>
    tclass
    {
        static const int id;
    };

    template <class T>
    int tclass<T>::id = counter::nexti();
#包括“counter.hpp”
模板
tclass
{
静态常量int-id;
};
模板
int tclass::id=counter::nexti();
它似乎在MSVC和GCC中正常工作,但有一个例外,就是不能在switch语句中使用它


由于各种原因,实际上我进一步定义了一个预处理器宏,该宏从给定的名称参数创建一个新的类,该类的静态ID(如上)来自一个公共基础。

< P>另一个备选方案是考虑下面的类<代码>数据< /代码>具有唯一的静态成员字段<代码>类型< /C> >:

template <class T>
class Data
{
public:
    static const std::type_index type;
};
// do [static data member initialization](http://stackoverflow.com/q/11300652/3041008)
// by [generating unique type id](http://stackoverflow.com/q/26794944/3041008)
template <class T>
std::type_index const Data<T>::type = std::type_index(typeid(T));
它不是一个整数id或可打印字符串,也不是一个
constexpr
,但可以是。

如果
Data.h
头包含在多个文件中(相同的
hashCode()
值),它似乎也可以工作。

可以使用源代码从字符串生成编译时哈希

如果可以修改模板以包含一个额外的整数,并使用宏声明变量:

template<typename T, int ID> struct A
{
    static const int id = ID;
};

#define DECLARE_A(x) A<x, COMPILE_TIME_CRC32_STR(#x)>

另一个缺点是可能发生哈希冲突。

几个月前我遇到了类似的问题。我正在寻找一种技术来定义每次执行时都相同的标识符。
如果这是一个要求,那么这是另一个或多或少探讨同一问题的问题(当然,这是一个很好的答案)。
无论如何,我没有使用建议的解决方案。它遵循我当时所做的描述


您可以定义如下所示的
constexpr
函数:

static constexpr uint32_t offset = 2166136261u;
static constexpr uint32_t prime = 16777619u;

constexpr uint32_t fnv(uint32_t partial, const char *str) {
    return str[0] == 0 ? partial : fnv((partial^str[0])*prime, str+1);
}

inline uint32_t fnv(const char *str) {
    return fnv(offset, str);
}
然后是这样一个要从中继承的类:

template<typename T>
struct B {
    static const uint32_t id() {
        static uint32_t val = fnv(T::identifier);
        return val;
    }
};
请注意,如果要在非常量表达式中使用
ID
,必须在某个地方定义
标识符,如下所示:

struct C: B<C> {
    static const char * identifier;
};

const char * C::identifier = "ID(C)";
constexpr char C::identifier[];
constexpr char D::identifier[];
一旦你做到了,你就可以这样做:

int main() {
    constexpr auto val = C::ID();
    // Now, it is well-formed
    auto ident = C::ID();

    // ...
}

这是一个C++代码,使用<代码>、ydAdEyth> 和 格式:

// __DATE__ "??? ?? ????"
// __TIME__ "??:??:??"
这是一个低质量的哈希函数:

template <typename T>
class A
{
public:
    static const unsigned int ID;
};

template <>
const unsigned int A<float>::ID = HASH();

template <>
const unsigned int A<double>::ID = HASH();

template <>
const unsigned int A<int>::ID = HASH();

template <>
const unsigned int A<short>::ID = HASH();

#include <iostream>

int main() {
    std::cout << A<float>::ID << std::endl;
    std::cout << A<double>::ID << std::endl;
    std::cout << A<int>::ID << std::endl;
    std::cout << A<short>::ID << std::endl;
}
使用哈希函数:

template <typename T>
class A
{
public:
    static const unsigned int ID;
};

template <>
const unsigned int A<float>::ID = HASH();

template <>
const unsigned int A<double>::ID = HASH();

template <>
const unsigned int A<int>::ID = HASH();

template <>
const unsigned int A<short>::ID = HASH();

#include <iostream>

int main() {
    std::cout << A<float>::ID << std::endl;
    std::cout << A<double>::ID << std::endl;
    std::cout << A<int>::ID << std::endl;
    std::cout << A<short>::ID << std::endl;
}
模板
甲级
{
公众:
静态常量无符号整数ID;
};
模板
常量unsigned int A::ID=HASH();
模板
常量unsigned int A::ID=HASH();
模板
常量unsigned int A::ID=HASH();
模板
常量unsigned int A::ID=HASH();
#包括
int main(){

我通常使用的是:

template<typename>
void type_id(){}

using type_id_t = void(*)();
模板
无效类型_id(){}
使用类型_id_t=void(*)();
constexpr char C::identifier[];
constexpr char D::identifier[];
int main() {
    constexpr auto val = C::ID();
    // Now, it is well-formed
    auto ident = C::ID();

    // ...
}
// __DATE__ "??? ?? ????"
// __TIME__ "??:??:??"
#define HASH_A 8416451
#define HASH_B 11368711
#define HASH_SEED 9796691    \
+ __DATE__[0x0] * 389        \
+ __DATE__[0x1] * 82421      \
+ __DATE__[0x2] * 1003141    \
+ __DATE__[0x4] * 1463339    \
+ __DATE__[0x5] * 2883371    \
+ __DATE__[0x7] * 4708387    \
+ __DATE__[0x8] * 4709213    \
+ __DATE__[0x9] * 6500209    \
+ __DATE__[0xA] * 6500231    \
+ __TIME__[0x0] * 7071997    \
+ __TIME__[0x1] * 10221293   \
+ __TIME__[0x3] * 10716197   \
+ __TIME__[0x4] * 10913537   \
+ __TIME__[0x6] * 14346811   \
+ __TIME__[0x7] * 15485863

unsigned HASH_STATE = HASH_SEED;
unsigned HASH() {
    return HASH_STATE = HASH_STATE * HASH_A % HASH_B;
}
template <typename T>
class A
{
public:
    static const unsigned int ID;
};

template <>
const unsigned int A<float>::ID = HASH();

template <>
const unsigned int A<double>::ID = HASH();

template <>
const unsigned int A<int>::ID = HASH();

template <>
const unsigned int A<short>::ID = HASH();

#include <iostream>

int main() {
    std::cout << A<float>::ID << std::endl;
    std::cout << A<double>::ID << std::endl;
    std::cout << A<int>::ID << std::endl;
    std::cout << A<short>::ID << std::endl;
}
template<typename>
void type_id(){}

using type_id_t = void(*)();
// Work at compile time
constexpr type_id_t int_id = type_id<int>;

// Work at runtime too
std::map<type_id_t, std::any> types;

types[type_id<int>] = 4;
types[type_id<std::string>] = "values"s

// Find values
auto it = types.find(type_id<int>);

if (it != types.end()) {
    // Found it!
}
#include<cstddef>
#include<functional>
#include<iostream>

template<typename T>
struct wrapper {
    using type = T;
    constexpr wrapper(std::size_t N): N{N} {}
    const std::size_t N;
};

template<typename... T>
struct identifier: wrapper<T>... {
    template<std::size_t... I>
    constexpr identifier(std::index_sequence<I...>): wrapper<T>{I}... {}

    template<typename U>
    constexpr std::size_t get() const { return wrapper<U>::N; }
};

template<typename... T>
constexpr identifier<T...> ID = identifier<T...>{std::make_index_sequence<sizeof...(T)>{}};

// ---

struct A {};
struct B {};

constexpr auto id = ID<A, B>;

int main() {
    switch(id.get<B>()) {
    case id.get<A>():
        std::cout << "A" << std::endl;
        break;
    case id.get<B>():
        std::cout << "B" << std::endl;
        break;
    }
}
constexpr auto id = ID<A, B>;
id.get<A>()
template<typename> struct noLonger { };
constexpr auto id = ID<noLonger<A>, B>;
constexpr auto id = ID<noLonger<void>, B>;
 #include <iostream>

 template<class> struct my_id_helper;
 #define DECLARE_ID(C) template<> struct my_id_helper<C> { enum {value = __COUNTER__ }; }

 // actually declare ids:
 DECLARE_ID(int);
 DECLARE_ID(double);
 // this would result in a compile error: redefinition of struct my_id_helper<int>’
 // DECLARE_ID(int);

 template<class T>
 class A
 {
 public:
     static const unsigned int ID = my_id_helper<T>::value;
 };

 int main()
 {
     switch(A<int>::ID)
     {
     case A<int>::ID:    std::cout << "it's an int!\n"; break;
     case A<double>::ID: std::cout << "it's a double!\n"; break;
     // case A<float>::ID: // error: incomplete type ‘my_id_helper<float>’
     default: std::cout << "it's something else\n"; break;
     }
 }
#include <iostream>
#include "meta_counter.hpp"

template<typename T, typename counter>
struct A
{
    static const size_t ID = counter::next();
};

int main () {
    typedef atch::meta_counter<void> counter;
    typedef A<int,counter> AInt;
    typedef A<char,counter> AChar;
    typedef A<bool,counter> ABool;
    switch (ABool::ID)
    {
        case AInt::ID:
            std::cout << "Int\n";
            break;
        case ABool::ID:
            std::cout << "Bool\n";
            break;
        case AChar::ID:
            std::cout << "Char\n";
            break;
    }

    std::cout << AInt::ID << std::endl;
    std::cout << AChar::ID << std::endl;
    std::cout << ABool::ID << std::endl;
    std::cout << AInt::ID << std::endl;
    while (1) {}
}
// author: Filip Roséen <filip.roseen@gmail.com>
// source: http://b.atch.se/posts/constexpr-meta-container

#ifndef ATCH_META_COUNTER_HPP
#define ATCH_META_COUNTER_HPP

#include <cstddef>

namespace atch { namespace {

  template<class Tag>
  struct meta_counter {
    using size_type = std::size_t;

    template<size_type N>
    struct ident {
      friend constexpr size_type adl_lookup (ident<N>);
      static constexpr size_type value = N;
    };

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

    template<class Ident>
    struct writer {
      friend constexpr size_type adl_lookup (Ident) {
        return Ident::value;
      }

      static constexpr size_type value = Ident::value;
    };

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

    template<size_type N, int = adl_lookup (ident<N> {})>
    static constexpr size_type value_reader (int, ident<N>) {
      return N;
    }

    template<size_type N>
    static constexpr size_type value_reader (float, ident<N>, size_type R = value_reader (0, ident<N-1> ())) {
      return R;
    }

    static constexpr size_type value_reader (float, ident<0>) {
      return 0;
    }

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

    template<size_type Max = 64>
    static constexpr size_type value (size_type R = value_reader (0, ident<Max> {})) {
      return R;
    }

    template<size_type N = 1, class H = meta_counter>
    static constexpr size_type next (size_type R = writer<ident<N + H::value ()>>::value) {
      return R;
    }
  };
}}

#endif /* include guard */
template <class T>
class A
{
public:
    static constexpr int ID() { return next(); }
};
class DUMMY { };
int main() {
    std::cout << A<char>::ID() << std::endl;
    std::cout << A<int>::ID() << std::endl;
    std::cout << A<BETA>::ID() << std::endl;
    std::cout << A<BETA>::ID() << std::endl;
    return 0;
}
1
2
3
3
template<typename T>
static void get_type_id() { void* x; new (x) T(); }
using type_id_t = void(*)();