考虑以下计划:
namespace NS2 {
class base { };
template<typename T>
int size(T& t) {
std::cout << "size NS2 called!" << std::endl;
return sizeof(t);
}
};
namespace NS1 {
class X : NS2::base { };
}
namespace NS3 {
template<typename T>
int size(T& t) {
std::cout << "size NS3 called!" << std::endl;
return sizeof(t) + 1;
}
template<typename T>
class tmpl
{
public:
void operator()() { size(*this); }
};
};
int main() +{
NS3::tmpl<NS1::X> t;
t();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的编译器(gcc 4.3.3)不编译程序,因为对size的调用是不明确的.名称空间NS2似乎被添加到类tmpl中的size调用的关联名称空间集合中.即使在阅读了ISI标准中有关Koenig …
我正在尝试为operator<<标准库容器的特定实例化编写重载,这些容器将存储在boost::variant.这是一个说明问题的小例子:
#include <iostream>
#include <vector>
std::ostream & operator<<( std::ostream & os, const std::vector< int > & ) {
os << "Streaming out std::vector< int >";
return os;
}
std::ostream & operator<<( std::ostream & os, const std::vector< double > & ) {
os << "Streaming out std::vector< double >";
return os;
}
#include <boost/variant.hpp>
typedef boost::variant< std::vector< int >, std::vector< double > > MyVariant;
int main( int argc, char * argv[] ) {
std::cout << MyVariant();
return …Run Code Online (Sandbox Code Playgroud) c++ boost operator-overloading variant argument-dependent-lookup
如何在构造函数初始化列表中启用ADL?例如,假设我有一个bignum具有命名空间级abs功能.现在我想编写一个类Foo,用传递给构造函数的实例的绝对值初始化其成员; 它应该使用命名空间级别,abs如果它存在,std::abs否则:
template<typename T>
struct Foo
{
T _data;
Foo(T data):
_data(abs(data)) // I want find abs with ADL here
{}
};
Run Code Online (Sandbox Code Playgroud)
无论如何,在类范围内禁止使用声明,我不想"污染"命名空间.如何启用ADL以使其在构造函数初始化列表中工作?
我有简单namespace,它有一个变量和一个函数.在main我尝试调用没有名称空间限定符的函数,并使用名称空间限定符调用变量.
namespace SAM
{
int p = 10;
void fun(int)
{
cout<<"Fun gets called";
}
}
int main()
{
fun(SAM::p);//why SAM::fun is not get called?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我不能称之为有趣,为什么它不符合ADL(依赖于参数的名称查找)?
我在Visual Studio中遇到以下错误.
'有趣':找不到标识符
如果我使用SAM::fun它,它的工作原理.
精简版:
如果我有这样的功能:
constexpr bool has_some_property(Foo) { return true; }
Run Code Online (Sandbox Code Playgroud)
有没有办法调用函数而不必实际实例化Foo?如果Foo不是默认可构造的话?
长卷版本:
安东尼威廉姆斯最近写了一篇文章,详细介绍了一套为任何enum class专门用于特定模板的对象启用的免费功能.它遵循类似的方案中<ios>,std::is_error_code其中一个专门用于用户定义的类型或值的模板,以允许enable_if启用某些功能.在Anthony的案例中:
template<>
struct enable_bitmask_operators<my_bitmask>{
static constexpr bool enable=true;
};
Run Code Online (Sandbox Code Playgroud)
然后在定义运算符时:
template<typename E>
typename std::enable_if<enable_bitmask_operators<E>::enable,E>::type
operator|(E lhs,E rhs){
Run Code Online (Sandbox Code Playgroud)
此技术的问题是模板特化必须与原始模板位于同一名称空间中,因此这不起作用:
namespace mystuff {
enum class Foo {
...
};
// Fail: wrong namespace
template<>
struct enable_bitmask_operators<Foo> : std::true_type {}
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用一个constexpr函数,该函数可以在与类相同的命名空间中解析:
namespace mystuff {
enum class Foo {
...
};
constexpr bool enable_bitmask_operators(Foo) { return …Run Code Online (Sandbox Code Playgroud) 依赖于参数的查找说:
对于类类型的参数(包括union),该集合包含... a)类本身b)...
那为什么printX找不到X?
#include<iostream>
using namespace std;
class A {
public:
static const int X = 1;
};
class B {
public:
static void printX(A a)
{
cout << "X is " << X << endl;
}
};
int main(int argc, char** argv)
{
A a;
B::printX(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud) struct B {};
struct C : B {};
void f(B){} // worse match than A::f<C>
struct A {
template<class T>
void f(T v) {
f(v); // #1
}
};
int main()
{
A{}.f(C{});
}
Run Code Online (Sandbox Code Playgroud)
在线激活ADL查找#1非常简单
{
using ::f;
f(v);
}
Run Code Online (Sandbox Code Playgroud)
我认为在没有using指令的情况下使代码失败的规则是:
[basic.lookup.argdep]/3设X是非限定查找生成的查找集,让Y为参数相关查找生成的查找集(定义如下).如果X包含
- (3.1)集体成员的声明,或
- (3.2)不是使用声明的块范围函数声明,或
- (3.3)既不是函数也不是函数模板的声明
那么Y是空的.[...]
因此,由于f非ADL查找找到的调用将找到A::f,这是一个类成员,ADL-lookup发现的重载将被丢弃.
哪个C++规则允许忽略3.1中的限制using声明,以使上面的代码编译?
我想我完全误解了必须应用规则[basic.lookup.argdep]/3的上下文,或者在理解名称查找过程中我可能有一个更大的隐藏漏洞.
c++ language-lawyer class-members argument-dependent-lookup c++17
考虑以下代码。在这里,如果我们std::begin对initializer_list显式使用未命名std::,则可以正常工作。如果我们省略了std::并begin在named上使用initializer_list,它也可以正常工作。但是,如果我们std::与第一种情况类似并省略其余部分,则它将无法编译。
#include <iostream>
#include <iterator>
void func(int len, const int* x)
{
for(int i=0;i<len;++i)
std::cout << x[i] << "\n";
}
int main()
{
{
// OK
func(5, std::begin({1,3,6,823,-35}));
}
{
// OK
auto&& list = {1,3,6,823,-35};
func(5, begin(list));
}
// {
// // Fails to compile
// func(5, begin({1,3,6,823,-35}));
// }
}
Run Code Online (Sandbox Code Playgroud)
我收到以下编译错误(在取消注释错误代码后):
test.cpp: In function ‘int main()’:
test.cpp:21:11: error: ‘begin’ was not declared in this …Run Code Online (Sandbox Code Playgroud) 假设我有一个扩展(STL)容器的类并提供了一个习惯的begin成员函数:
#include <vector>
template <typename Cont>
struct Bar {
Cont c;
auto my_begin() { return begin(c); }
};
int main() {
Bar<std::vector<int>> b;
b.my_begin();
}
Run Code Online (Sandbox Code Playgroud)
通过ADL,我不必std::在begin()调用前指定。这很好,因为std::begin(v)总是尝试调用v.begin(),用户可能想要使用没有.begin()接口的自定义容器,因此如果他定义了自己的自由函数begin(v),Bar就会使用它。但是,如果我也重命名my_begin为ADL,似乎 ADL 将不再起作用begin,就好像它被掩盖了一样。编译器只会抱怨它在类范围内找不到匹配的调用:
prog.cc: In instantiation of 'auto Bar<Cont>::begin() [with Cont = std::vector<int>]':
prog.cc:11:13: required from here
prog.cc:6:27: error: use of 'auto Bar<Cont>::begin() [with Cont = std::vector<int>]' before deduction of 'auto'
6 | auto begin() …Run Code Online (Sandbox Code Playgroud) 当参数类型位于命名空间中时,可以省略sstd::的命名空间(通常是这种情况)。<algorithm>是否有任何警告或整齐的规则可以发现此类遗漏?
#include <vector>
#include <algorithm>
std::vector<int> v;
for_each(v.begin(), v.end(), [](auto){});
return 0;
Run Code Online (Sandbox Code Playgroud)
上面的示例使用最新的 clang 和 -Wall、-Wextra 和 -Wpedantic 编译,不会发出任何诊断信息:
c++ ×10
c++11 ×3
templates ×3
boost ×1
c++17 ×1
clang-tidy ×1
constexpr ×1
g++ ×1
variant ×1
visual-c++ ×1