【问题标题】:Clang wants me to write ::std::declval rather than std::declvalClang 要我写 ::std::declval 而不是 std::declval
【发布时间】:2019-08-01 10:25:18
【问题描述】:

我第一次尝试在 mac 中使用 clang 编译我的 repo。 Clang 为 std 命名空间的所有用法提供错误。它总是说使用 ::std::whatever 而不是 std::whatever。我在 ADL 或其他方面做错了吗?

如果有人想查看完整源代码,请访问repo

当我将它编写为 ::std::whatever 时它会编译,但我想知道为什么它强制我添加全局范围解析运算符?

template <typename S, typename T>
class implements_left_stream
{
     template <typename SS, typename TT>
     static auto test ( int )
     -> decltype ( std::declval<SS &>() << std::declval<TT>(), std::true_type() );

     template <typename, typename>
     static auto test ( ... ) -> std::false_type;

public:
     static const bool value = decltype ( test<S, T> ( 0 ) ) ::value;
};

错误是:

speech/util.h:34:20: error: no template named 'declval' in namespace 'speech::impl::std'; did you mean '::std::declval'?
[build]      -> decltype ( std::declval<SS &>() << std::declval<TT>(), std::true_type() );
[build]                    ^~~~~~~~~~~~
[build]                    ::std::declval
[build] /Library/Developer/CommandLineTools/usr/include/c++/v1/type_traits:1147:1: note: '::std::declval' declared here
[build] declval() _NOEXCEPT;

【问题讨论】:

  • 请创建一个minimal reproducible example 向我们展示(在问题正文中),它必须包含您#include 的头文件。
  • 作为您的问题的可能提示,想想您在哪里做#include &lt;cxxabi.h&gt;...
  • 最后,总是显式地包含声明或定义函数和结构的文件。对于std::declval,它是&lt;utility&gt;。在包含它(在任何命名空间之外)的同时,您也可能会解决您的问题。
  • 为什么在命名空间中包含头文件?为什么不在全局范围内做this

标签: c++ clang


【解决方案1】:

您正在尝试使用qualified name lookup。编译器在当前命名空间中查找并向上遍历,直到找到所需的命名空间 std。如果找到它,它将仅在该名称空间中搜索被调用函数。例如

namespace a {
namespace std { // <--
    std::cout << ... // will only search in current namespace a::std
}
}

namespace a {
namespace std { // <--
namespace b {
    std::cout << ... // will only search in parent namespace a::std
}
}
}

namespace a {
namespace b {
    std::cout << ... // will only search in namespace ::std
}
}

// Error, can't find a::std::func
namespace a {
namespace std {
    void func() {};
namespace std { // <--
    std::func() // will only search in current namespace a::std::std, not in a::std
}
}
}

// Error, can't find std::declval
#include <utility>
namespace speech {
namespace impl {
namespace std { } // <-- Namespace created by include cxxabi.h
    decltype ( std::declval<SS &>() << std::declval<TT>(), std::true_type() ); // will only search in parent namespace speech::impl::std
}
}

您的命名空间 speech::impl::std 会影响命名空间 std

编译器在找到一个同名的命名空间后不会向上遍历,即使这会产生错误。

编辑:

查看您的代码后,我看到您创建了命名空间speech::impl。在这个命名空间中,您包含头文件 cxxabi.h 并使用 apple-clang 进行编译。这创建了命名空间 speech::impl::std,它隐藏了命名空间 std

cxxabi.h for apple-clang 包含以下行

namespace std {
    class type_info; // forward declaration
}

【讨论】:

  • 应该提到这个问题源于#include &lt;someStdHeader&gt;,而在某个命名空间内而不是在全局范围内。
  • @MaxLanghof 这与包含无关。看我的第四个例子
  • 但是代码并没有定义speech::impl::std,反正不是单独定义的。并且std::declval 函数不是从std 命名空间内调用的。
  • 它与包含有关,因为这就是 namespace std 进入 namespace impl 的方式。我并不是说你错了,只是问题的根源在于 #include 不在全球范围内。
  • @MaxLanghof 现在我想我在查看代码后理解了它。
【解决方案2】:

根据错误消息,您有namespace speech::impl::std 并且位于命名空间namespace speech::impl 中(或有相应的using)。

所以命名空间std 指的是speech::impl::std,而不是预期的::std

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    相关资源
    最近更新 更多