在我的项目中,我有很多枚举,需要有与枚举成员相关的其他属性和与枚举类型相关的辅助静态方法.
据我所知,这对于标准枚举类MyItem {...}是不可能的,所以对于我项目中的每个枚举类,我有一个辅助类MyItemEnum,它封装了这些辅助静态方法,并且还实例化了辅助实例本身,以便我可以访问他们的方法,以获得其他属性.
Bellow一个例子(尽可能简化,但我相信所讨论的所有功能都在那里).
MyItem.h
enum class MyItem : unsigned int {
Item1 = 1,
Item2 = 5
};
class MyItemEnum {
private:
MyItem myItem;
size_t extInfo;
MyItemEnum(const MyItem& myItem, size_t extInfo);
~MyItemEnum();
public:
static MyItemEnum Item1;
static MyItemEnum Item2;
static const MyItemEnum &get(MyItem myItem);
operator MyItem() const;
size_t getExt() const;
bool hasNext() const;
MyItem next() const;
};
Run Code Online (Sandbox Code Playgroud)
我认为意思是显而易见的,我不需要在这里提供.cpp部分...当我需要访问扩展功能时,我使用MyItem作为参数在接口和MyItemEnum中传递.
我的第一个问题是,上面的方法是否正常,或者我应该考虑一些完全不同的东西?
我的第二个问题涉及我使用constexpr尝试做的这个枚举的优化:
enum class MyItem : unsigned int {
Item1 = 1,
Item2 = 5
};
class MyItemEnum {
private:
MyItem …Run Code Online (Sandbox Code Playgroud) 为了支持可移植性,我想根据size_t32位或64位的事实选择一个常量.代码:
using namespace std;
namespace detail {
template<enable_if<is_same<size_t, uint32_t>::value,void*>::type = nullptr>
constexpr static const size_t defaultSizeHelper() {
return ( (size_t) 1 << 30 ) / 2 * 5; //2,5 Gb
}
template<enable_if<is_same<size_t, uint64_t>::value,void*>::type = nullptr>
constexpr size_t defaultSizeHelper() {
return numeric_limits<size_t>::max() / 2;
}
}
constexpr static size_t defaultSize = detail::defaultSizeHelper();
Run Code Online (Sandbox Code Playgroud)
由于这个代码不能编译 error: 'std::enable_if<false, void*>::type' has not been declared. template<enable_if<is_same<size_t, uint64_t>::value,void*>::type = nullptr>
编译器 - GCC 4.9
在我看来,编译器不会将SFINAE原则应用于a constexpr.那我该怎么办?
我正在尝试将C++文字字符串转换为以下模板的实例:
template <char ... C>
struct string_literal {
typedef string_constant type;
static constexpr const char value[sizeof...(C)] = {C...};
constexpr operator const char* (void) const {
return value;
}
};
template <char ... C>
constexpr const char string_literal<C...>::value[sizeof...(C)];
Run Code Online (Sandbox Code Playgroud)
我想出了基于各种来源的这些帮助器,用于将引用的字符串值"解包"到上面的模板中.
template <unsigned N, const char (&S) [N], typename U>
struct selector;
template <unsigned N, const char (&S) [N], unsigned ...I>
struct selector<N, S, index_sequence<I...>> {
using type = string_literal<S[I]...>;
};
template <unsigned N, const char (&S) [N]>
struct unpack {
using type …Run Code Online (Sandbox Code Playgroud) string-literals template-meta-programming variadic-templates constexpr c++11
最近我试图利用MSVC 2015下的C++ 0x constexpr,我的目标是实现编译时哈希字符串.我编写了一个简单的FNV-1a哈希算法作为constexpr函数,根据需要使用单个return语句(三元运算符)并仅调用constexpr函数,这里它是:
template <size_t N>
constexpr U32 StringID_FNV1a_32(const char(&str)[N], I32 charIndex = 0, U32 hash = 2166136261U)
{
return charIndex < N-1 ? StringID_FNV1a_32(str, charIndex +1, (hash ^ str[charIndex]) * 16777619U) : hash;
}
Run Code Online (Sandbox Code Playgroud)
我还做了一个小宏,能够毫不费力地改变引擎盖下的算法:
#define STRING_ID(str) core::utility::StringID_FNV1a_32(str)
Run Code Online (Sandbox Code Playgroud)
然后我在我的代码中使用了这个宏,仔细检查是否有任何断点被击中,以及生成的汇编代码.这是小情景:
//1. normal variable test
U32 hash1 = STRING_ID("abc");
//2. enum test
enum {
hash2 = STRING_ID("abc")
};
//3. constexpr variable test
constexpr U32 hash3 = STRING_ID("abc");
Run Code Online (Sandbox Code Playgroud)
这里有事实:
你可以想象我对第一次和第三次尝试感到有些困惑.
为什么在第三种情况下允许编译器在运行时调用该函数?即使msdn明确说明"const和constexpr变量之间的主要区别在于const变量的初始化可以推迟到运行时,而constexpr变量必须在编译时初始化." [ https://msdn.microsoft.com/it-it/library/dn956974.aspx#Anchor_3] …
考虑以下代码:
struct foo
{
static constexpr int value = 42;
};
void bar(const int* value) { std::cout << *value; }
int main() { bar(&foo::value); }
Run Code Online (Sandbox Code Playgroud)
编译没有问题,并没有在警告夫妇的在线编译器我试过了.鉴于没有.cpp定义该constexpr值的单个文件,如果bar从不同的编译单元调用该方法,指针的值是否可以不同?或者标准是否保证值最终只在所有编译单元中分配一次(即隐式_declspec(selectany))?
我有一个模板函数,有一点我想根据模板参数使用不同的代码:
template <typename T>
void function(const T ¶m) {
// generic code here...
// pseudo-code:
if constexpr isinstance(param, Banana) {
param.peel();
} else if constexpr isinstance(param, Apple) {
// do nothing, Apple has no method `peel`
}
}
Run Code Online (Sandbox Code Playgroud)
我不想专门研究整个功能,因为大多数代码都是共享的。我要插入的语句实际上是一种临时调试措施。我知道正确的做法是创建一个重载函数,doPeel然后调用它:
void doPeel(const Banana ¶m) { param.peel(); }
void doPeel(const Apple ¶m) {}
Run Code Online (Sandbox Code Playgroud)
但是我很好奇,有没有一种方法可以在编译时告诉函数中某个给定变量的类型(模板专门化)是什么...以便使用仅针对一种类型进行编译的语句?
我不知道这样的事情是否可以实现constexpr-还是编译器在废弃分支中强制执行类型?我还尝试使用lambda进行处理-为这两种情况都定义lambda,并且仅调用其中一种,但是我找不到解决方法。有任何想法吗?
考虑以下代码:
#include <unordered_set>
#include <type_traits>
#include <cstring>
constexpr auto cstring_hash(const char* istring) -> size_t {
return (*istring) == '\0' ?
size_t(0):
(*istring) + cstring_hash(istring + 1);
}
constexpr auto cstring_length(const char* istring) -> size_t {
return (*istring) == '\0' ?
size_t(0):
size_t(1) + cstring_length(istring + 1);
}
class PrehashedString {
public:
constexpr PrehashedString(const char* istring)
: str_(istring)
, hash_(cstring_hash(istring))
, size_(cstring_length(istring)) {
}
constexpr auto& get_hash() const { return hash_; }
auto operator==(const PrehashedString& iother) const {
return
size_ == …Run Code Online (Sandbox Code Playgroud) 请看下面的代码,抱歉有点冗长,但我尽力用最小的例子重现问题(还有它的实时副本).在那里我基本上有一个返回字符串文字大小的元函数,以及包装它的constexpr函数.然后当我在模板参数中调用这些函数时,gcc(5.4,6.2)对它很满意,但是在测试体中,clang(3.8,3.9)barfs与"非类型模板参数不是常量表达式" strsize(s).如果我用str_size<S>两个编译器替换都很高兴.所以问题是:
这是clang或我的代码有问题吗?
使用constexpr函数在clang和gcc上编译它的方法是什么?
template<size_t N> using string_literal_t = char[N];
template<class T> struct StrSize; ///< metafunction to get the size of string literal alikes
/// specialize StrSize for string literals
template<size_t N>
struct StrSize <string_literal_t<N>>{ static constexpr size_t value = N-1; };
/// template variable, just for convenience
template <class T>
constexpr size_t str_size = StrSize<T>::value;
/// now do the same but with constexpr function
template<class T>
constexpr auto strsize(const T&) noexcept-> decltype(str_size<T>) {
return …Run Code Online (Sandbox Code Playgroud)我有一个constexpr从字符串文字计算CRC32哈希的函数。
template <size_t len>
constexpr uint32_t ctcrc32(const char (&str)[len]) {
return detail::crc32<len - 2>(str) ^ 0xFFFFFFFF;
}
Run Code Online (Sandbox Code Playgroud)
(指其他constexpr功能)
我想做的是调用其他一些接受uint32_t值的函数,并使用它访问某些中的数据unordered_map。这样的调用看起来像这样:
uniformByNameCRC32(ctcrc32("uPointLight.position"));
Run Code Online (Sandbox Code Playgroud)
我希望"uPointLight.position"的哈希值在构建时进行一次计算,然后将结果常量传递给uniformByNameCRC32(),但事实并非如此,并ctcrc32()在运行时被调用,这基本上会杀死CPU,因为我有很多uniformByNameCRC32()调用。
但是,这很好用:
std::array<uint64_t, ctcrc32("string_literal")> array;
Run Code Online (Sandbox Code Playgroud)
这样的代码将编译并指示ctcrc32()的返回值确实是一个constexpr。
我在这里想念什么?
考虑一下这个简单的测试代码:
class Test
{
public:
Test() {/* empty */}
private:
enum {BLAH = 42};
static constexpr int Magic() {return BLAH*4;}
float f[Magic()];
};
int main(int argc, char ** argv)
{
Test t;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译它时(使用最新的XCode中的clang ++在MacOS/X下),我得到了这个编译错误:
Jeremys-Mac-Pro:~ jaf$ clang++ -std=c++11 ./test.cpp
./test.cpp:11:14: error: fields must have a constant size: 'variable length
array in structure' extension will never be supported
float f[Magic()];
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释为什么这是一个错误?为了比较,如果我将Magic()方法移出Test类并使其成为一个独立的函数,它会按预期编译,但我真的不想那样做,因为我想保留Magic()和BLAH如果可能,私有到Test类.
(注意:我不是在这里尝试使用可变长度数组;而是我试图声明一个数组,其大小由编译时函数的计算决定)
constexpr ×10
c++ ×7
c++11 ×4
templates ×4
c++14 ×1
clang ×1
compile-time ×1
enable-if ×1
enum-class ×1
hash ×1
lto ×1
visual-c++ ×1