我有这段代码使用iostreams'pword
和void*&
来存储各种类型的标志作为指针。由于#include <iostream>
#include <string>
using namespace std::literals;
void*& pword()
{
static void* ptr;
return ptr;
}
const std::string*& sword()
{
return (const std::string*&) pword();
}
int main()
{
const auto s1 = "foo"s;
const auto s2 = "bar"s;
sword() = &s1;
std::cerr << *sword() << '\n';
sword() = &s2;
std::cerr << *sword() << '\n';
}
公开了一个void*
,我有一个简单的包装器来通过一个旧的C cast来公开存储的类型。但是从第5版开始,clang发出了一个我不太了解的警告。我不明白如何避免它。简单的测试用例如下:
clang++-mp-devel -std=c++17 -Wcast-qual foo.cc && ./a.out
foo.cc:14:32: warning: cast from 'void *' to 'const std::string *&' (aka 'const basic_string<char,
char_traits<char>, allocator<char> > *&') must have all intermediate pointers const qualified
to be safe [-Wcast-qual]
return (const std::string*&) pword();
^
1 warning generated.
foo
bar
我收到的警告(似乎忘记了const std::string*& sword2()
{
return static_cast<const std::string*&>(pword());
}
上的引用):
foo.cc:19:10: error: non-const lvalue reference to type 'const std::string *' (aka 'const
basic_string<char, char_traits<char>, allocator<char> > *') cannot bind to a value of
unrelated type 'void *'
return static_cast<const std::string*&>(pword());
^ ~~~~~~~
另外,我没有看到如何使用C ++强制转换而不是C全能转换。明显的尝试:
{{1}}
以错误结束我不明白。该错误似乎暗示编译器可能觉得有必要在某处插入副本,打破引用链,但我不知道在哪里以及为什么。
{{1}}
答案 0 :(得分:1)
这相当于一个着名的事实,即您无法将char**
转换为const char**
- 因为它会允许
const char cc='a';
const char *cp=&cc;
char *p;
const char **pp=&p; // error in question
*pp=cp; // i.e., p=&cc;
*p='z'; // oops
在这种情况下,通过将void*
描述为const std::string*
,您可以存储指向常量字符串的指针(就像您一样),然后在{{1}上使用static_cast
获取指向字符串的非void*
指针。
答案是使用const
添加 const_cast
然后(如HolyBlackCat所说)const
(然后小心不要尝试修改字符串!):
reinterpret_cast
除了const-correctness之外,我现在还不记得是否通过这样的const std::string*& sword()
{
return reinterpret_cast<const std::string*&>(const_cast<const void*&>(pword()));
}
将T*
存储到void*
变量中是明确的行为;然而,它是人们期望在常见实现中工作的东西。