我正在使用gcc 4.6.1并且正在获得一些涉及调用constexpr函数的有趣行为.这个程序运行得很好,直接打印出来12200160415121876738.
#include <iostream>
extern const unsigned long joe;
constexpr unsigned long fib(unsigned long int x)
{
return (x <= 1) ? 1 : (fib(x - 1) + fib(x - 2));
}
const unsigned long joe = fib(92);
int main()
{
::std::cout << "Here I am!\n";
::std::cout << joe << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这个程序需要永远运行,我从来没有耐心等待它打印出一个值:
#include <iostream>
constexpr unsigned long fib(unsigned long int x)
{
return (x <= 1) ? 1 : (fib(x - 1) + …Run Code Online (Sandbox Code Playgroud) 是否可以为constexpr变量分配唯一的地址,即对于变量可用的所有翻译单元(通常通过标题)都是相同的?请考虑以下示例:
// foo.hh
#include <iostream>
constexpr int foo = 42;
// a.cc
#include "foo.hh"
void a(void) { std::cout << "a: " << &foo << std::endl; }
// b.cc
#include "foo.hh"
extern void a(void);
int main(int argc, char** argv) {
a();
std::cout << "b: " << &foo << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
使用gcc 4.7 编译a.cc和b.cc分开并将它们链接在一起,我看到打印了两个不同的地址.如果我extern在标题中添加关键字,我会收到链接器错误duplicate symbol _foo in: a.o and b.o,我觉得有点令人惊讶,因为我认为添加extern更有可能导致编译器从另一个对象导入该符号,而不是从当前对象导出它.但似乎我对这些事情的运作方式的理解是错误的.
是否有合理的方法在一个标题中声明constexpr,这样所有翻译单元都可以在其常量表达式中使用它,并且所有翻译单元都同意该符号的地址?我希望一些额外的代码来表示这个符号实际所属的单个翻译单元,就像没有的extern非extern变量一样constexpr.
出于某种原因,clang ++(但不是g ++)抱怨:
constexpr double invdecayf1m(double x) {
return -log1p(-x);
}
Run Code Online (Sandbox Code Playgroud)
告诉我
non-constexpr function 'log1p' cannot be used in a constant expression
return -log1p(-x);
Run Code Online (Sandbox Code Playgroud)
为什么在所有声明的常用数学函数<cmath>都不是" constexpr函数"?
请考虑以下代码:
static constexpr int make_const(const int i){
return i;
}
void t1(const int i)
{
constexpr int ii = make_const(i); // error occurs here (i is not a constant expression)
std::cout<<ii;
}
int main()
{
t1(12);
}
Run Code Online (Sandbox Code Playgroud)
为什么我在make_const调用时出错?
UPDATE
但是这个有效:
constexpr int t1(const int i)
{
return make_const(i);
}
Run Code Online (Sandbox Code Playgroud)
但是,这不是:
template<int i>
constexpr bool do_something(){
return i;
}
constexpr int t1(const int i)
{
return do_something<make_const(i)>(); // error occurs here (i is not a constant expression)
}
Run Code Online (Sandbox Code Playgroud) 在尝试使用constexpr函数和模板(以及非类型模板参数)时,我偶然发现了一个现象,我无法理解哪个规则使它生效.
因此,根据有关constexpr-s的规则,我的问题基本上是"为什么会发生这种情况"."这个"如下.
在其中一个constexpr函数中,如果直接使用参数,则在编译时计算中使用此参数没有问题.(示例第2行)
当相同的参数用作另一个constexpr函数的参数时,编译器会抱怨此表达式(参数id)不是constexpr.(例子第3行)
简而言之:
template <typename T> constexpr std::size size (T obj) { return obj.size(); }
template <typename T> constexpr auto sz1 (T obj) { return std::make_index_sequence< obj.size() > { }.size(); } // OK ...
template <typename T> constexpr auto sz2 (T obj) { return std::make_index_sequence< size(obj) > { }.size(); } // ERROR
// "obj" is [suddenly] not a constexpr
Run Code Online (Sandbox Code Playgroud)
g ++ - 4.9.1和clang ++ - 3.4.2都会发生这种情况.
下面是一个小型测试程序,用于快速简便的实验.
#include <utility>
#include <array>
#include <iostream>
// utils
template <size_t N> …Run Code Online (Sandbox Code Playgroud) 是否有可能在C++中有这样的东西:
struct Foo
{
int x;
constexpr Foo(int x) : x(x) {}
static constexpr Foo table[] =
{
Foo(0),
Foo(1),
Foo(2),
};
};
Run Code Online (Sandbox Code Playgroud)
我尝试了几种组合,但都没有效果.如果table不是Foo类的一部分,它可以工作,但我真的希望它成为Foo命名空间的一部分.
编辑:
我想要这个的原因是我可以访问表格Foo::table.我在命名空间中有几个这样的类,如果我可以通过编写导入我正在使用的类using someNamespace::Foo然后访问该表,这非常方便Foo::table.如果表在课外,我必须始终通过写作来访问它someNamespace::fooTable.
我目前正在与Visual Studio 2017进行斗争(/std:c++latest如果有任何帮助,请编译使用).
有问题的代码只是根据一些模板化constexpr函数的结果选择结构特化.GCC和clang编译它没有问题.
这是我的MCVE:
#include <type_traits>
struct A {
enum {
test_trait = true
};
};
template<typename T>
constexpr int choose() {
return T::test_trait;
}
template<typename T, typename Enable=void>
struct Chosen;
template<typename T>
struct Chosen<T, std::enable_if_t<choose<T>() == 1>> {};
void foo() {
// This works
constexpr int chosen = choose<A>();
static_assert(chosen == 1, "");
// This resolves to the undefined struct.
using Chosen_t = Chosen<A>;
Chosen_t x;
(void)x;
}
Run Code Online (Sandbox Code Playgroud)
choose()在我的代码库中实际上有点复杂,但static_assert仍然编译,并检查正常.
我有点假设,如果static_assert …
我有一个带有int模板参数的类.在某些情况下,我希望它输出一条错误消息.此消息应该是来自某些固定文本和模板参数的串联字符串.出于性能原因,我希望每次发生错误时都避免在运行时构建此字符串,理论上两者都是,字符串文字和模板参数在编译时是已知的.所以我正在寻找将其声明为constexpr的可能性.
代码示例:
template<int size>
class MyClass
{
void onError()
{
// obviously won't work but expressing the concatenation like
// it would be done with a std::string for clarification
constexpr char errMsg[] = "Error in MyClass of size " + std::to_string (size) + ": Detailed error description\n";
outputErrorMessage (errMsg);
}
}
Run Code Online (Sandbox Code Playgroud) constexpr int get () { return 5; }
template<int N> struct Test {};
int main ()
{
int a[get()]; // ok
Test< get() > obj; // error:'int get()' cannot appear in a constant-expression
}
Run Code Online (Sandbox Code Playgroud)
我用ideone编译了这段代码.并且想知道为什么它会给出编译错误.是constexpr不允许函数作为template参数,还是编译器中的错误?
编辑:更改const int get()为int get()
此外,还有一个与ideone的错误是,如果你删除constexpr然后仍然声明一个数组是允许的!我认为这是一个C99功能.
有没有办法用C++ 11功能替换Xmacro习语,最好不要使用预处理器?我认为可以使用元组模板,但我仍然试图弄清楚这些是如何工作的.