【问题标题】:Disabling pointer output in C++ streams?在 C++ 流中禁用指针输出?
【发布时间】:2011-05-23 07:49:28
【问题描述】:

如果您将任何指针传递给 C++ 流,它的地址将被放入输出中。 (显然,除非有更具体的输出处理程序。)

void* px = NULL;
const char* ps = "Test";
FooType* pf = ...;
stringstream s;
s << ps << " " << px << " " << pf "\n";
s.str(); // yields, for example: "Test 0 AF120089"

如果用户错误地尝试实际打印 FooType 的 ,这可能是一个问题。

而且在混合宽字符和窄字符时也是一个问题,因为不是编译器错误,而是打印地址:

const wchar_t* str = L"Test! (Wide)";
// ...
cout << str << "\n"; // Ooops! Prints address of str.

所以我想知道 - 因为我很少想要输出指针值,是否可以禁用指针值的格式化,以便将指针值插入流中会导致编译器错误?(然后可以通过使用包装类型或将指针值强制转换为 size_t 或类似的方式轻松实现指针值的输出。)

编辑:鉴于Neil's answer(通过提供我自己的 void* 输出运算符来禁用 void* 输出)我想补充一点,如果这也适用于诸如Boost.Format,隐式使用std 命名空间中定义的输出运算符...

【问题讨论】:

    标签: c++ iostream


    【解决方案1】:

    operator&lt;&lt; 的全局模板版本似乎可以工作:

    #include <iostream>
    #include <boost/static_assert.hpp>
    
    template<typename T>
    std::ostream & operator<<(std::ostream & stream, T* value) {
        BOOST_STATIC_ASSERT(false);
    }
    
    int main() {
        int foo = 5;
        int * bar = &foo;
    
        std::cout << bar << std::endl;
    }
    

    编辑:此解决方案无法按预期工作,因为模板还捕获字符串文字。您应该更喜欢@Neil 的解决方案。

    【讨论】:

    • 酷,看起来我们想出了几乎相同的答案!
    • 这不会仅限于全局命名空间中的代码吗?看起来其他命名空间中的代码会找到 ::std::operator&lt;&lt;(由于 std::cout 上的 ADL)而不是 ::operator&lt;&lt;
    • @MSalters:在ideone it works 上,即使调用来自另一个命名空间。但直觉上我会同意你的。
    • 奇怪:T* 的关联命名空间是 T 的命名空间; int 没有关联的命名空间(基本类型),所以 int* 也没有。我们显然忽略了一些东西。
    • 啊,忘了:全局命名空间是每个命名空间的外部命名空间。当在内部命名空间中找到 no 匹配项时,将搜索外部命名空间(这意味着此 operator&lt;&lt; 被内部命名空间中的任何 operator&lt;&lt; 隐藏 - 但 the example 没有)
    【解决方案2】:

    如果未注释 cout 的第二个和/或第三个输出,这会在 g++ 中产生编译错误:

    #include <iostream>
    using namespace std;
    
    ostream & operator << ( const ostream &, void * ) {
    }
    
    
    int main() {
        int n = 0;
        cout << 0;
    //  cout << &n;
    //  cout << (void *) 0;
    }
    

    【讨论】:

    • 嗯……这看起来不错。 “正常”的 void* 输出运算符是在命名空间 std 中定义的,不是吗?因此,如果有代码使用来自 std 的代码,这将无济于事......?
    • 有点工作,但在形式上你不允许在没有至少一种用户定义的参数类型的情况下重载运算符。
    • @Bo 你认为 ostream 是什么?
    • @nbt:C++ 标准对于 std 中的内容是否是“用户定义的”模糊不清,有时它以一种方式使用该术语,有时使用另一种方式。
    【解决方案3】:

    是的,您可以通过提供自己的 ostream 运算符重载 来导致编译错误

    #include <iostream>
    
    template <typename T>
    std::ostream& operator << (std::ostream& s, T* p)
    {
      char ASSERT_FAILED_CANNOT_OUTPUT_POINTER[sizeof(p) - sizeof(p)];
    }
    
    int main()
    {
       int x;
       int* p = &x;
       cout << p;
    }
    

    【讨论】:

    • 正如我在编辑自己的答案时提到的,这不能按预期工作,因为它还会阻止您打印字符串文字。
    【解决方案4】:

    保持operator &lt;&lt; 未实现指针。

    template<typename T>
    std::ostream& operator<<(std::ostream &stream, T* value);
    

    编辑:或者最好输入无效的类型名以获取编译器错误。

    【讨论】:

    • 这会导致链接器错误,而不是编译器错误,不是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 2013-04-14
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    相关资源
    最近更新 更多