English 中文(简体)
连续休息
原标题:Compile-time constant id

考虑到:

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

我想国际发展研究中心为每个T.I ve(http://code>_COUNTER_和增强型发展图书馆制作一个独特的汇编时间,但迄今未能成功。 我如何能够做到这一点?

Edit: ID has to be usedable as the case in achange statement

Edit2:基于固定方法或成员地址的所有答案都是不正确的。 虽然它们的确创造了一个独一无二的识别资料,但它们在汇编时间时没有解决,因此不能作为开关说明的个案。

问题回答

这足以假定符合汇编者的标准(关于一项定义规则):

template<typename T>
class A
{
public:
    static char ID_storage;
    static const void * const ID;
};

template<typename T> char A<T>::ID_storage;
template<typename T> const void * const A<T>::ID= &A<T>::ID_storage;

C++标准 3.2.5 一条定义规则[基本原理](原强调地雷):

... If D is a template and is defined in more than one translation unit, then the last four requirements from the list above shall apply to names from the template’s enclosing scope used in the template definition (14.6.3), and also to dependent names at the point of instantiation (14.6.2). If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

我通常使用的是:

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!
}

这对我来说似乎非常有用:

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;

}

利用静态功能的记忆地址。

template<typename T>
class A  {
public:
    static void ID() {}
}; 

(&A<int>:ID)将不同于(&A<char>:ID)等。

Using this constant expression counter:

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;
}

产出(GCC, C++14)

1
2
3
3

倒数是,你将需要对固定的反工作表达方式的衍生类别数目进行gues商。

I encountered this exact problem recently. My solution:

counter.hpp

class counter
{
    static int i;
    static nexti()
    {
        return i++;
    }
};

反对:

int counter::i = 0;

页: 1

#include "counter.hpp"

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

    template <class T>
    int tclass<T>::id = counter::nexti();

该公司评估员在特别志愿人员委员会和海合会中开展适当工作,但有一项例外,即你可以在换函中加以利用。

For various reasons I actually went further, and defined a preprocessor macro that creates a new class from a given name parameter with a static ID (as above) that derives from a common base.

Here is a possible solution mostly based on templates:

#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;
    }
}

请注意,这需要C++14。

你们都必须把ids子与种类清单联系起来,以便把该清单作为模板变量,如上所示:

constexpr auto id = ID<A, B>;

从那时起,你可以通过<条码>/获得特定类型的补贴。 方法:

id.get<A>()

所有这一切都是如此。 您可根据请求并在示范守则中表明,可在<代码>switch说明中使用。

Note that, as long as types are appended to the list of classes to which associate a numeric id, identifiers are the same after each compilation and during each execution.
If you want to remove a type from the list, you can still use fake types as placeholders, as an example:

template<typename> struct noLonger { };
constexpr auto id = ID<noLonger<A>, B>;

This will ensure that A has no longer an associated id and the one given to B won t change.
If you won t to definitely delete A, you can use something like:

constexpr auto id = ID<noLonger<void>, B>;

Or whatever.

Ok.....so this is a hack that I found from this website. It should work. The only thing you need to do is add another template parameter to your struct that takes a counter "meta-object". Note that A with int, bool and char all have unique IDs, but it is not guaranteed that int s will be 1 and bool will be 2, etc., because the order in which templates are initiated is not necessarily known.

另一项说明:

这将不与微软视像C++合作。

#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
";
            break;
        case ABool::ID:
            std::cout << "Bool
";
            break;
        case AChar::ID:
            std::cout << "Char
";
            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) {}
}

http://code>meta_counter.hpp:

// 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 */

采用模板,如果从中得出,则需要C++17

#include <iostream>

template <typename Type, typename... Types>
struct TypeRegister{
    template<typename Queried_type>
    static constexpr int id(){
        if constexpr (std::is_same_v<Type, Queried_type>) return 0;
        else{
            static_assert((sizeof...(Types) > 0), "You shan t query a type you didn t register first");
            return 1 + TypeRegister<Types...>::template id<Queried_type>();
        }
    }
};

int main(){
    using reg_map = TypeRegister<int, float, char, const int&>;
    std::cout << reg_map::id<const int&>() << std::endl;// 3
    // std::cout << reg_map::id<const int>() << std::endl;// error
}

不能这样做。 对静态物体的地址是,最接近的,但为了处理这些物体(即使是静态成分),必须加以界定。 如果是一条定义规则,则应在CPP档案中加以界定,因为该档案是模板,无法做到这一点。 如果你在主人档案中界定静态,那么每个汇编单位将采用自己的版本,当然使用不同的地址。

I had a similar problem a few months ago. I was looking for a technique to define identifiers that are the same over each execution.
If this is a requirement, here is another question that explores more or less the same issue (of course, it comes along with its nice answer).
Anyway I didn t use the proposed solution. It follows a description of what I did that time.


您可确定<代码>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);
}

Then a class like this from which to inherit:

template<typename T>
struct B {
    static const uint32_t id() {
        static uint32_t val = fnv(T::identifier);
        return val;
    }
};

CRTP idiom does the rest.
As an example, you can define a derived class as it follows:

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

const char * C::identifier = "ID(C)";

As long as you provide different identifiers for different classes, you will have unique numeric values that can be used to distinguish between the types.

无需认证员参加衍生课程。 举例来说,你可以通过海峡提供:

template<typename> struct trait;
template<> struct trait { static const char * identifier; };

// so on with all the identifiers

template<typename T>
struct B {
    static const uint32_t id() {
        static uint32_t val = fnv(trait<T>::identifier);
        return val;
    }
};

Advantages:

  • Easy to implement.
  • No dependencies.
  • Numeric values are the same during each execution.
  • Classes can share the same numeric identifier if needed.

缺点:

  • Error-prone: copy-and-paste can quickly become your worst enemy.

It follows a minimal, working example of what has been described above.
I adapted the code so as to be able to use the ID member method in a switch statement:

#include<type_traits>
#include<cstdint>
#include<cstddef>

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

template<std::size_t I, std::size_t N>
constexpr
std::enable_if_t<(I == N), uint32_t>
fnv(uint32_t partial, const char (&)[N]) {
    return partial;
}

template<std::size_t I, std::size_t N>
constexpr
std::enable_if_t<(I < N), uint32_t>
fnv(uint32_t partial, const char (&str)[N]) {
    return fnv<I+1>((partial^str[I])*prime, str);
}

template<std::size_t N>
constexpr inline uint32_t fnv(const char (&str)[N]) {
    return fnv<0>(offset, str);
}

template<typename T>
struct A {
    static constexpr uint32_t ID() {
        return fnv(T::identifier);
    }
};

struct C: A<C> {
    static constexpr char identifier[] = "foo";
};

struct D: A<D> {
    static constexpr char identifier[] = "bar";
};

int main() {
    constexpr auto val = C::ID();

    switch(val) {
    case C::ID():
        break;
    case D::ID():
        break;
    default:
        break;
    }
}

请指出,如果你想要使用<条码>ID,则你必须把<条码>识别码/代码>中的某些部分定义为:

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++代码,使用_DATE____TIME_>/code>。 获取<代码><T>独特标识的宏观

<>>Format:

// __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;
}

If non-monotonous values and an intptr_t are acceptable:

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;

如果你必须ts,或者必须具有单质的增量价值,我认为,使用静态构造是唯一的出路:

// 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;

请注意,如果你在共享图书馆和你的申请之间分享这些技术,这两种技术都不会安全。

另一种备选办法是审议以下类别:<代码>Data,其中列有独一无二的静态成员领域<代码> 类型:

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));

produces the output (MinGWx64-gcc4.8.4 -std=c++11 -O2)

printf("%s %s
", Data<int>::type.name(), Data<float>::type.name())
//prints "i f"

It s not exactly an integer id or pretty-printable string, nor a constexpr, but can be used as an index in (un)ordered associative containers.
It also appears to work if the Data.h header is included in multiple files (same hashCode() values).

Here is a pragmatic solution, if you are ok with writing a single additional line DECLARE_ID(type) for each type you want to use:

 #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!
"; break;
     case A<double>::ID: std::cout << "it s a double!
"; break;
     // case A<float>::ID: // error: incomplete type ‘my_id_helper<float>’
     default: std::cout << "it s something else
"; break;
     }
 }
template<typename T>
static void get_type_id() { void* x; new (x) T(); }
using type_id_t = void(*)();

优化工作





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签