静态断言非常便于在编译时检查事物.一个简单的静态断言习惯用法如下:
template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};
#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)
Run Code Online (Sandbox Code Playgroud)
这对于像这样的东西很有用
STATIC_ASSERT(sizeof(float) == 4)
Run Code Online (Sandbox Code Playgroud)
和:
#define THIS_LIMIT (1000)
...
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT);
Run Code Online (Sandbox Code Playgroud)
但是使用#define不是定义常量的"C++"方式.C++会让你使用匿名命名空间:
namespace {
const int THIS_LIMIT = 1000;
}
Run Code Online (Sandbox Code Playgroud)
甚至:
static const int THIS_LIMIT = 1000;
Run Code Online (Sandbox Code Playgroud)
这样做的问题在于,const int你不能使用STATIC_ASSERT(),你必须采用愚蠢的运行时检查.
有没有办法在当前的C++中正确解决这个问题?
我想我已经读过C++ 0x有一些工具可以做到这一点......
编辑
好的,这个
static const int THIS_LIMIT = 1000;
...
STATIC_ASSERT(THIS_LIMIT > 0);
Run Code Online (Sandbox Code Playgroud)
编译好
但是这个:
static const float THIS_LIMIT = 1000.0f;
...
STATIC_ASSERT(THIS_LIMIT > 0.0f);
Run Code Online (Sandbox Code Playgroud)
才不是.
(在Visual …
为什么constexpr变量的decltype失败?
#include <cstdint>
#include <type_traits>
constexpr uint16_t foo(){ return 0;}
constexpr auto cv = foo();
auto v = foo();
static_assert( std::is_same< uint16_t, decltype(cv)>::value, "!"); // failed
static_assert( std::is_same< uint16_t, decltype(v) >::value, "!"); // success
Run Code Online (Sandbox Code Playgroud) 如果给出类型I的声明不包含Q_OBJECT宏,我有一些有趣的需要显示编译错误.我找到了一种不好的方法.实际上它重复了Qt开发人员做同样伎俩的想法:
template<typename T>
void checkForQObjectMacro()
{
reinterpret_cast<T *>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T *>(0));
}
Run Code Online (Sandbox Code Playgroud)
这很好用,但它确实给出了奇怪的错误信息.我想展示一条可读的消息.一种方法是使用static_assert构造.但我不知道如何实现Q_OBJECT宏存在的静态验证条件.也许有人可以提出一个漂亮的黑客?也非常感谢任何想法.
更新
我发布了一份工作草案,rebind作为问题的答案.虽然我没有太多运气找到一种通用的方法来防止static_assert破坏元功能.
基本上我想检查是否T<U, Args...>可以从其他类型构造模板化类型T<V, Args...>.其中T和Args...是在这两种类型相同.问题是,T<>可能有一个static_assert完全打破我的元功能.
以下是我正在尝试做的粗略总结.
template<typename T>
struct fake_alloc {
using value_type = T;
};
template<typename T, typename Alloc = fake_alloc<T>>
struct fake_cont {
using value_type = T;
// comment the line below out, and it compiles, how can I get it to compile without commenting this out???
static_assert(std::is_same<value_type, typename Alloc::value_type>::value, "must be the same type");
};
template<typename T, typename U, typename = …Run Code Online (Sandbox Code Playgroud) template<typename T, typename U = void>
struct S { /* static_assert(0, "type unsupported"); */ };
template<typename T>
struct S<T, typename std::enable_if<std::is_integral<T>::value, void>::type> {
void foo() {}
};
...
S<int> i;
i.foo();
S<double> d;
// d.foo();
Run Code Online (Sandbox Code Playgroud)
我希望"主模板"永远不会被实例化int,但如果我取消注释static_assert,S<int>实例化将失败.即使是单独的typedef S<int> Si;也无法编译.(GCC 4.9.2 Cygwin)
我想要实现的不是S<double>在foo()调用时失败,而是在模板本身的实例化中,以及带有意义的错误消息.我知道我可以typename T::nonexistent_type t;在主模板中执行某些操作,这将阻止模板进行编译,但这不如static_assert消息.(注意:将static_assert函数定义放在主模板中仍然无法编译S<int>)
为什么static_assert即使该模板未实例化也会失败?这个标准是强制性的(或者可能是"未指明的")吗?有没有办法以static_assert我想要的方式失败?
这个问题的灵感来自我之前的问题没有模板参数扣除参数包.
请考虑以下代码示例:
#include <memory>
#include <string>
template<typename... FArgs>
class Callback
{
public:
class Handle{};
};
class BaseCallbackHandle
{
};
using TypeErasedCallbackHandle = std::unique_ptr<BaseCallbackHandle>;
template<typename H>
TypeErasedCallbackHandle makeTypeErasedCallbackHandle( H handle)
{
return {};
}
int main()
{
Callback<int>::Handle h;
std::string s;
makeTypeErasedCallbackHandle(h); //should compile fine
makeTypeErasedCallbackHandle(s); //should raise a compile error
}
Run Code Online (Sandbox Code Playgroud)
另见http://coliru.stacked-crooked.com/a/5f2a2e816eef6afd
函数模板makeTypeErasedCallbackHandle现在将任何类作为输入参数.有没有办法确保(例如使用static-assert或enable_if),只允许Callback<FArgs...>::Handle(有任何FArgs)H?Callback<int>::Handle应该编译的例子,但是std::string会失败.
当表达式取决于类类型本身时,有没有办法在类内进行 static_assert ?也许延迟评估直到类型完成或模板实例化之后?
示例代码:
#include <type_traits>
template<typename T>
struct Test {
T x = 0; // make non-trivial
static_assert(std::is_trivial<Test<T>>::value, "");
};
int main() {
// would like static assert failure, instead get 'incomplete type' error
Test<int> test1;
Test<float> test2;
return 0;
}
Run Code Online (Sandbox Code Playgroud) template<typename T> struct S {};
template<typename T> struct R {};
int main() {
typedef S<double> s1;
typedef S<int> s2;
typedef R<int> s3;
static_assert(xxx<s1, s2>::value,
"No, assertion must not be raised");
static_assert(xxx<s2, s3>::value,
"Yes, assertion must be raised");
}
Run Code Online (Sandbox Code Playgroud)
所以,我希望在编译时返回false xxx<s1, s2>::value而xxx<s2, s3>::value返回true.
在C++中是不是存在xxx?或者,在C++中理论上是否存在xxx,但可能还没有人做过呢?
有没有办法使用检测习惯用法(或另一种方法)来测试一个函数是否对给定的模板参数有效,如果它由于static_assert?而失败?
下面的例子说明了foo(失败的返回类型计算)的有效性是按预期检测到的,但是bar(失败的static_assert)的有效性则没有.
#include <iostream>
#include <type_traits>
template <typename... T> using void_t = void;
template <class AlwaysVoid, template<class...> class Op, class... Args>
struct detector: std::false_type { };
template <template<class...> class Op, class... Args>
struct detector<void_t<Op<Args...>>, Op, Args...>: std::true_type { };
template <template<class...> class Op, class... Args>
constexpr bool is_detected = detector<void, Op, Args...>::value;
template <typename T>
std::enable_if_t<!std::is_void<T>::value> foo() {
std::cout << "foo" << std::endl;
}
template <typename T>
void bar() { …Run Code Online (Sandbox Code Playgroud) 我知道有一个针对constexpr()运算符的提议,但这尚未在gcc / clang中实现。我也知道使用一些技巧来实现,例如机器代码编辑:
http://saadahmad.ca/detecting-evaluation-context-inside-constexpr-functions/
我想知道是否有某种受限的解决方案:
struct F {
constexpr F(int v) {
if constexpr(constexpr()) {
static_assert(v > 0);
}
else {
assert(v > 0);
}
}
};
// ...
constexpr F f{0}; // should trigger a compile-time error
Run Code Online (Sandbox Code Playgroud)
我知道无法以这种方式使用static_assert,但这只是为了澄清问题。