【问题标题】:Resolve std::string to something else than ::std::string - is it possible?将 std::string 解析为 ::std::string 以外的其他内容 - 可能吗?
【发布时间】:2019-10-11 09:45:15
【问题描述】:

这是来自: constructing string from NULL?

的后续问题

以下内容:

void test(const std::string& s);

int main(){
  test(NULL);
}

运行时失败,但合法 c++。

为了尝试捕捉其中一些情况,作为替代方案,我考虑是否可以通过以下方式替换 std::string

#include <string>


namespace {
namespace std {
    struct string : public ::std::string { //so far everything is good

    };
}
}


int main ()
 {
   std::string hello;//failure: ambiguous symbol

   return 0;
 }

给出以下错误:

<source>(17): error C2872: 'std': ambiguous symbol

C:/data/msvc/14.22.27905/include\string(19): note: could be 'std'

<source>(7): note: or       '`anonymous-namespace'::std'

<source>(17): error C2872: 'std': ambiguous symbol

C:/data/msvc/14.22.27905/include\string(19): note: could be 'std'

<source>(7): note: or       '`anonymous-namespace'::std'

Compiler returned: 2

我想如果不写一个更(完全)合格的名称就不可能解决它?但是是否可以在全局命名空间中写入 std::string 并让它解析为其他东西,而 ::std::string is 是一个有效类型。

背景:在尝试使用 cppcheck 和 cpp 核心检查失败后,我试图找到所有 std::string str = 0NULLnullptr 的案例 - 因为这些案例将在运行时失败。我认为这可能是一个前进的方向。

我最终修改了 basic_string 模板。 basic_string(int) = delete; basic_string(::std::nullptr_t) = delete; - 这不会捕获所有案例,但似乎确实至少可以捕获直接案例

【问题讨论】:

  • 我首先要问 - 为什么要将 std::string 查找解析为其他内容?
  • @bartop 查看问题的最后一部分,背景
  • 你为什么要“抓住”它?那有什么意思?为什么std::string str = 0 首先出现在您的代码中?您为什么不修复这些代码错误,而不是尝试编写一个尝试隐藏错误的自定义类型?很抱歉一堆问题,但您似乎有一个 XY 问题,最好详细解释您的情况和目标。不要向我们展示您的(尝试)解决方案,向我们展示您的问题。
  • 一些额外的想法:如果您担心正则表达式无法在您的代码中找到此问题的所有情况 - 您如何确保能够在每个地方注入此自定义类型它需要在哪里的代码?如果你想用一个自定义类型替换std::string,它会默默地忽略nullptr 分配,为什么不简单地用MyCustomNullPtrSafeString 替换代码库中所有出现的std::string,而不是一个名为std::string 的自定义类型?
  • 您的问题也应该是独立的。如果阅读您发布的其他问题或其他外部信息有助于全面了解您的情况,您可能需要链接到该外部信息并在您的问题中进行总结。

标签: c++ c++17 static-analysis argument-dependent-lookup


【解决方案1】:

std::string 解析为::std::string 以外的其他内容 - 可能吗?
[...]
...作为替代方案,我考虑是否可以通过以下方式替换 std::string...

据我所知,不可能在您的匿名命名空间范围之外,因为您无法解决歧义(据我所知)。

如下所示,既然你在匿名命名空间的范围内,那就没问题了:

#include <string>

namespace
{
    namespace std
    {
        struct string : public ::std::string
        {

        };
    }
    std::string hello; // Fine
}


int main()
{
    std::string hello2; // Cannot be something else that ambiguous

    return 0;
}

但更糟糕的是,问题不在于std::string 本身,而在于std 命名空间。

确实,在您的匿名命名空间范围之外,std 的每次调用也会变得模棱两可。
这是编译器指出的错误。有两个 std 命名空间可以从全局范围内访问。

所以下面的例子就坏了:

#include <string>
#include <vector>

namespace
{
    namespace std
    {
        struct string : public ::std::string
        {

        };
    }
    std::string hello; // Fine
}


int main()
{
    std::vector<int> a; // FAIL: reference to 'std' is ambiguous

    return 0;
}

要解决在访问原始 std 命名空间时出现的歧义,您需要将其编写如下:

::std::vector<int> a; // Fully qualified name: Only way to refer to the `::std` namespace

如您所见,它仍然没有解决问题,更糟糕的是,它增加了巨大的不便。


所以道德是:

  • 不要隐藏已经存在的类型,而是创建一个不同的类型。
  • 同样,不要隐藏命名空间(通过将相同的命名空间定义为匿名命名空间 --> 邪恶)。

(我对这个答案的任何改进建议持开放态度)

【讨论】:

  • 您可以将::std 的所有内容 导入到您自己的std 命名空间中,这样歧义并非不可克服,只是非常不方便。
  • @MSalters 但是我们仍然会遇到第一个案例错误(string 被导入到他自己的std 命名空间中),不是吗?如果我误解了您的评论,请告诉我。
  • 实际上没有一个示例 import ::std::string;相反,他们定义了另一个继承自::std::stringstring。 IE。不是namespace { namespace std { using string = ::std::string; }}。所以我认为你误解了我的评论,是的。
  • @MSalters 好吧,我现在明白你的意思了。但它仍然不能按原样编译。此外,OP 想重新定义std::string
  • 我很确定 darune 并没有试图重新定义 std::string。我怀疑您并不完全熟悉 C++ 标准中使用的措辞?例如。 “单一定义规则”? AFAICT,目标是影响std::string名称查找。由于这涉及两个名称,因此有两个名称查找。
【解决方案2】:

您可以使用这种解决方案吗:您不是在 std::string 上工作,而是在会导致问题的函数上工作

#include <string>

void test(const std::string& s){

}
// add a new function which use a pointer : 
void test (const char* _Nonnull s) {
    test(std::string(s));

}
int main()
{
    test(NULL);
    return 0;
}

然后clang会产生一个警告: 生成了 1 个警告。

ASM generation compiler returned: 0

<source>:13:14: warning: null passed to a callee that requires a non-null argument [-Wnonnull]

test(NULL);

https://godbolt.org/z/PujFor

【讨论】:

  • 我最终修改了 basic_string 模板 ala。 ` basic_string(int) = 删除; basic_string(::std::nullptr_t) = delete;` - 这不会捕获所有情况,但似乎确实至少可以捕获直接情况
  • _Nonnull 不是标准 c++ afaik 吗?
  • @darune 不是特定于 clang 的:对于 gcc,它是 __attribute__((nonnull)) 对于 Microsoft 是 __assume。标准 c++11 及更高版本具有执行编译时断言检查的 static_assert。
  • @darune 您可以添加您的解决方案作为此问题的答案。
  • @darune 确实,微软编译器似乎没有提供与 gcc 和 clang 相同的检查级别(虽然 __assume 没有像我第一次那样检查)。根据这个问题:stackoverflow.com/questions/38641514/… MSVC 仅使用假设作为提示。我没有找到任何方法来进行编译时检查:我发现的只是运行时检查,这不是你想要的
猜你喜欢
  • 1970-01-01
  • 2021-10-30
  • 2016-01-28
  • 2016-01-06
  • 1970-01-01
相关资源
最近更新 更多