有没有办法用C++ 11功能替换Xmacro习语,最好不要使用预处理器?我认为可以使用元组模板,但我仍然试图弄清楚这些是如何工作的.
任何人都可以试着解释一下吗?
template<typename T, size_t S = T::noElems()>
struct C
{
};
struct X
{
enum E { A, B, C };
static constexpr size_t noElems() { return C+1; };
};
struct K
{
C<X> cx; // this DOES compile
};
struct Y
{
struct Z
{
enum E { A, B, C };
static constexpr size_t noElems() { return C+1; };
};
C<Z, Z::C+1> cyz; // this DOES compile
C<Z> cyz; // <--- this does NOT compile
};
Run Code Online (Sandbox Code Playgroud) #include <iostream>
#include <array>
int main(int argc, char **argv) {
constexpr const std::array<int, 2> arr {{ 0, 1 }};
constexpr const int arr2[] = { 0, 1};
static_assert(arr[0] == arr2[0], "asdf");
static_assert(arr[1] == arr2[1], "asdfasdf");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当编译gcc 4.8.2和4.9.1使用g++ test.cpp --std=c++11,编译成功.当编译clang 3.4和3.5利用clang++ test.cpp --std=c++11然而,编译失败:
test.cpp:8:16: error: static_assert expression is not an integral constant expression
static_assert(arr[0] == arr2[0], "asdf");
^~~~~~~~~~~~~~~~~
test.cpp:8:16: note: non-constexpr function 'operator[]' cannot be used …Run Code Online (Sandbox Code Playgroud) 在下面的C++ 11代码中,对arraySize的最后一次调用会导致编译错误.显然这是因为y是运行时大小的数组,并且不能推导出y的arraySize模板参数N. 我不明白为什么x是一个编译时大小的数组,但y结束了运行时大小.arraySize模板函数直接取自Scott Meyers的"Effective Modern C++"第1项.
#include <cstddef>
template<typename T, std::size_t N>
constexpr std::size_t arraySize(T(&)[N]) noexcept { return N; }
struct S
{
char c[10];
};
int main()
{
S s;
S* ps = &s;
char x[arraySize(s.c)];
char y[arraySize(ps->c)]; // why is y a runtime sized array?
arraySize(x);
arraySize(y); // error !?
return 0;
}
Run Code Online (Sandbox Code Playgroud) 在放宽constexpr的规则之后,似乎这些功能可以在任何地方使用.它们也可以在常量(constexpr)和局部(可变)变量上调用.所以对我来说,它似乎只是编译器的一个提示(如内联).我只是继续在任何地方写它并在编译器抱怨时删除它.因此,如果可以在编译时评估函数,编译器似乎知道所有内容.为什么它不是默认行为,为什么我必须将任何东西标记为constexpr?
根据n4487和其他c ++ 17引用,将会有新的lambda函数说明符 - constexpr如果存在,则"明确指定函数调用运算符是一个constexpr函数." .我理解lambda中常量表达式的动机.对我来说有趣的是提案的第4点,其中指出:
4)如果
constexpr在lambda声明符中省略了说明符,则函数调用运算符(或模板)constexpr是否满足constexpr函数的要求.
这引出了两个问题:
constexpr说明符?看起来lambda调用操作符是否将constexpr取决于它"满足constexpr函数的要求"的事实,而不是来自 constexpr说明符的存在.constexpr默认情况下可以接受lambda,那么为什么不建议其他类型的函数 - 例如全局函数?如果编译器开始处理涵盖需求的所有函数,会产生什么影响constexpr?我习惯用定义我的常量enum { my_const = 123; },因为在类中,使用static constexpr需要在类定义之外的一些代码(参见这个问题).但是 - 功能体呢?最近我注意到人们只是constexpr在他们的功能中有变量(const实际上甚至没有打扰他们),我想知道我是不是一个傻瓜谁是我的时代背后
int foo(int x)
{
enum : int { bar = 456 };
return x + bar;
}
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是:在函数体中使用枚举而不是constexpr变量有什么好处吗?
实际上这个"问题"感觉非常简单.在做一些计算出的图标偏移时,我想出了以下方法:
namespace Icons {
struct IconSet {
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2) {
}
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
constexpr size_t next() const {
return base_offset_ + 1;
}
};
static constexpr IconSet flower = IconSet(0);
static constexpr IconSet tree = IconSet(flower.next());
static constexpr IconSet forest = IconSet(tree.next());
static constexpr IconSet mountain = IconSet(forest.next());
}
Run Code Online (Sandbox Code Playgroud)
现在可以编写一个Icons::tree.iconBig例子来获取该图标的计算偏移量.基本上,设计师可以更改图标 - 有时也可以添加/删除 - 但总是按惯例提供整个设置(正常,小和大).
如你所见,这种方法的问题是我必须做这个next()功能并重复使用它 - 正常的枚举不会有这个缺点. …
考虑一个简单的例子:
int foo() {
return 3;
}
template <int>
struct Bar {};
int a;
int main() {
int b;
//Bar<((void)foo(), 1)> bar1; //case 1. compilation error as expected
Bar<((void)a, 2)> bar2; //case 2. no error (long shot but `a' has a linkage so maybe expected)
Bar<((void)b, 3)> bar3; //case 3. no error ? (`b' does not have linkage)
(void)bar2;
(void)bar3;
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,我想写:
constexpr std:map<std::string, std::string> my_map =
{{"key1", "val1"}, {"key2", "val2"}, };
Run Code Online (Sandbox Code Playgroud)
要么
constexpr std:unordered_map<std::string, std::string> my_map =
{{"key1", "val1"}, {"key2", "val2"}, };
Run Code Online (Sandbox Code Playgroud)
但是都不可能(至少在当前语言c ++ 17中是不可能的)
那还有什么选择呢?
例如,我可以做以下事情:
constexpr std::initializer_list< std::pair<const char*, const char *> > my_map =
{{"key1", "val1"}, {"key2", "val2"}, };
Run Code Online (Sandbox Code Playgroud)
然后在运行std::map时需要时构造一个。我知道我也可以使用inline代替constexpr,但是那时我将无法在编译时使用(也许在开发的后期)。但是,这有点不令人满意(因为我不得不在运行时仅出于查找目的构造映射),我想知道:是否有更好的解决方案?