Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编译期间是否可以生成常量值?_C++_Visual Studio 2008_Visual C++_Compiler Construction - Fatal编程技术网

C++ 编译期间是否可以生成常量值?

C++ 编译期间是否可以生成常量值?,c++,visual-studio-2008,visual-c++,compiler-construction,C++,Visual Studio 2008,Visual C++,Compiler Construction,我希望我的类通过一个唯一的哈希代码来标识每种类型。但我不希望每次在运行时调用一个方法(例如,int GetHashCode())时都生成这些散列。我想使用已经生成的常量,我希望有一种方法可以让编译器进行一些计算并设置这些常量。可以使用模板来完成吗?如果可能的话,你能给我举个例子吗 更新: 感谢“评论”,我意识到我的问题应该是这样的: 如何以尽可能低的运行时成本进行类型检查? 我想根据类类型检查指向对象的指针。只是我在libs中实现的类,所以我考虑了一些自定义哈希,这就是最初的问题。我确实考虑过使

我希望我的类通过一个唯一的哈希代码来标识每种类型。但我不希望每次在运行时调用一个方法(例如,
int GetHashCode()
)时都生成这些散列。我想使用已经生成的常量,我希望有一种方法可以让编译器进行一些计算并设置这些常量。可以使用模板来完成吗?如果可能的话,你能给我举个例子吗

更新:

感谢“评论”,我意识到我的问题应该是这样的: 如何以尽可能低的运行时成本进行类型检查?


我想根据类类型检查指向对象的指针。只是我在libs中实现的类,所以我考虑了一些自定义哈希,这就是最初的问题。我确实考虑过使用<代码> Type ID>代码>,但我不知道使用它的运行时成本。我做了一个假设,因为typeid生成了一个
type\u info
类,它比唯一int值的简单比较更消耗。

您可以使用它。

我会走一条简单的路线:

  • 对于将是静态属性的类,只需为每个类选择一个数字
  • 例如,只需使用地址即可

静态常量是在编译时进行计算的,这在很大程度上是元编程的基础。此外,type_info::hash_代码特别适合您的需要,所以请尝试-

class MyClass
{
static const size_t TypeHashCode = typeid(MyClass).hash_code();
...
}
(我现在不熟悉编译器,因此这可能需要一些改进。我将尝试明天重新检查)


编辑:事实上,它不仅是微软特有的,而且只在VS2010中添加了——但是,嘿,至少微软同意这是一个有效的需求。如果您的代码中不同时允许VS2010和boost,那么您就只剩下符合标准的功能:typeid或dynamic_cast。它们确实会产生一些开销,但我会特别注意验证这一开销确实是一场有价值的战斗。(我的钱花在了-不是。)

所有这些课程都有共同点。那么为什么不在一个公共枚举中为每个类添加一个符号常量呢?您可以让枚举为您提供值,这比提供显式常量容易(您仍然需要在枚举中声明每个类)。

模板
结构为类提供\u哈希\u代码\u
{
公众:
静态uintpttr_t GetHashCode()
{
返回(重新解释铸件(未使用)(&U));
}
私人:
静态空隙*未使用;
};
模板
void*为\u类::unused提供\u散列\u代码\u;
类MyClass:public为类提供\u散列\u代码\u
{
};
int main()
{
标准::库特尼古拉·费迪索夫在路线上建造:

  • 对于将是静态属性的类,请使用转换为的函数的地址来提供唯一但已编译的值
  • 例如,只需使用地址即可

标准不支持编译时类型的哈希代码,这是一个小问题。作为一种解决方法,可以从类名生成编译时哈希。下面是一个示例

#include <stdint.h>
#include <string>
#include <vector>
#include <iostream>
#include <memory>
#include <cassert>

//Compile-time string hashing.
class HashedString
{
public:
    typedef int64_t HashType;
    explicit constexpr HashedString(const char* str):  m_hash(hashString(str)) {}

    static inline constexpr HashType hashString(const char* str)
    {
        return ( !str ? 0 : hashStringRecursive(5381, str));
    }
    static inline constexpr HashType hashStringRecursive(HashType hash, const char* str)
    {
        return ( !*str ? hash : hashStringRecursive(((hash << 5) + hash) + *str, str + 1));
    }
    const HashType m_hash;
};

struct EventBase
{
    using IdType = HashedString::HashType;

    virtual ~EventBase() {}
    IdType getId() const {  return m_eventId;  }       //present the runtime event id

    EventBase(IdType myId) : m_eventId { myId } { }

    template<class DerivedEvent>
    const DerivedEvent* getAs() const
    {
        return dynamic_cast<const DerivedEvent*>(this);
    }

protected:
    const IdType m_eventId;
};

#define DEFINE_EVENT_ID(className) \
static constexpr IdType id = HashedString(#className).m_hash;   \

struct SomeEvent1 : public EventBase
{
    DEFINE_EVENT_ID(SomeEvent1);

    SomeEvent1(int status) : EventBase(id), m_status { status } { assert(id == m_eventId);  }
    int m_status;
};


struct SomeEvent2 : public EventBase
{
    DEFINE_EVENT_ID(SomeEvent2);

    SomeEvent2() : EventBase(id) { assert(id == m_eventId); }
    std::string m_s = "test event 2";
};

void testEvents()
{
    std::vector<std::shared_ptr<EventBase>> events;

    events.push_back(std::make_shared<SomeEvent1>(123));
    events.push_back(std::make_shared<SomeEvent2>());

    for (auto event : events) {
        switch(event->getId()) {
            case SomeEvent1::id:
                std::cout << "SomeEvent1 " << event->getAs<SomeEvent1>()->m_status << std::endl;
                break;
            case SomeEvent2::id:
                std::cout << "SomeEvent2 " << event->getAs<SomeEvent2>()->m_s << std::endl;
                break;
        }
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
//编译时字符串哈希。
类HashedString
{
公众:
typedef int64_t HashType;
显式constexpr HashedString(const char*str):m_hash(hashString(str)){
静态内联constexpr HashType hashString(const char*str)
{
返回(!str?0:hashStringRecursive(5381,str));
}
静态内联constexpr HashType hashStringRecursive(HashType hash,const char*str)
{
return(!*str?hash:hashStringRecursive((hash getId()){
案例SomeEvent1::id:

std::cout m_status可能是预编译器中的某个内容,但是没有关于预编译器哈希函数和/或随机数的具体想法。为什么您认为需要这样做?如果您获取hashcode()方法返回一个常量并内联。它不会在运行时真正被调用,但肯定会被编译器内联。没有运行时成本。不必费心寻找复杂的解决方法,只需信任编译器……在我的Symbian时代,我们使用编译后构建工具将各种ID注入ROM;我们喜欢简单的哈希预处理器本可以完成的系统,而不是试图跟踪占位符并将其外部化。您可以显示用于获取哈希代码的接口吗?GetHashCode是一个方法还是独立函数?您将已生成的常量保存在何处?在类内还是其他地方?我会在您的操作过程中处理实例检查说(某些情况除外),但为每个类选择一个数字对我来说不是一个选项。我正在开发3个可以单独或合作的库,我不想每次创建一个类时检查一个数字是否在所有3个库中都是唯一的。对不起,我不想使用boost。我应该在我的问题中提到这一点。使用枚举是我当前的解决方案,但我想改变我的想法因为为了满足我的需要,这样的枚举应该可以扩展到我的库之外。从MyClass派生的类具有与基相同的哈希代码,这是不可接受的。使用provide_hash_code_for_class会导致编译错误C2385:“GetHashCode”的访问不明确。这是一个很好的观点。您可能可以使用“Using provide_hash”来消除符号的歧义_在您正在编写的类中为_class::GetHashCode'编写代码,但这太多了……我想trait type类是不可能的,因为您可能不想更改接口?
#include <stdint.h>
#include <string>
#include <vector>
#include <iostream>
#include <memory>
#include <cassert>

//Compile-time string hashing.
class HashedString
{
public:
    typedef int64_t HashType;
    explicit constexpr HashedString(const char* str):  m_hash(hashString(str)) {}

    static inline constexpr HashType hashString(const char* str)
    {
        return ( !str ? 0 : hashStringRecursive(5381, str));
    }
    static inline constexpr HashType hashStringRecursive(HashType hash, const char* str)
    {
        return ( !*str ? hash : hashStringRecursive(((hash << 5) + hash) + *str, str + 1));
    }
    const HashType m_hash;
};

struct EventBase
{
    using IdType = HashedString::HashType;

    virtual ~EventBase() {}
    IdType getId() const {  return m_eventId;  }       //present the runtime event id

    EventBase(IdType myId) : m_eventId { myId } { }

    template<class DerivedEvent>
    const DerivedEvent* getAs() const
    {
        return dynamic_cast<const DerivedEvent*>(this);
    }

protected:
    const IdType m_eventId;
};

#define DEFINE_EVENT_ID(className) \
static constexpr IdType id = HashedString(#className).m_hash;   \

struct SomeEvent1 : public EventBase
{
    DEFINE_EVENT_ID(SomeEvent1);

    SomeEvent1(int status) : EventBase(id), m_status { status } { assert(id == m_eventId);  }
    int m_status;
};


struct SomeEvent2 : public EventBase
{
    DEFINE_EVENT_ID(SomeEvent2);

    SomeEvent2() : EventBase(id) { assert(id == m_eventId); }
    std::string m_s = "test event 2";
};

void testEvents()
{
    std::vector<std::shared_ptr<EventBase>> events;

    events.push_back(std::make_shared<SomeEvent1>(123));
    events.push_back(std::make_shared<SomeEvent2>());

    for (auto event : events) {
        switch(event->getId()) {
            case SomeEvent1::id:
                std::cout << "SomeEvent1 " << event->getAs<SomeEvent1>()->m_status << std::endl;
                break;
            case SomeEvent2::id:
                std::cout << "SomeEvent2 " << event->getAs<SomeEvent2>()->m_s << std::endl;
                break;
        }
    }
}