C++ 0x的ranged-for循环有一个处理数组的特殊异常(FDIS§6.5.4),并且有两个函数std :: begin和end,它们被重载以处理数组或选择开始/结束方法.这使我相信可以编写接受通用序列的函数来匹配ranged-for循环的行为:
template<class C>
void f(C &c) {
using std::begin;
using std::end;
do_something_with(begin(c), end(c));
}
Run Code Online (Sandbox Code Playgroud)
如果在C的命名空间中有一个"更具体"的开始/结束,它将通过ADL选择,否则代码"默认"为std :: begin/end.
但是,有一个原因,因为有特殊例外.如果在命名空间中传递一个类型的数组,其中一个语义不同的begin/end接受一个指针,则不会选择std :: begin/end的数组形式:
namespace ns {
struct A {};
void begin(A*); // Does something completely different from std::begin.
}
void f_A() { // Imagine above f() called with an array of ns::A objects.
ns::A c[42];
using std::begin;
begin(c); // Selects ns::begin, not array form of std::begin!
}
Run Code Online (Sandbox Code Playgroud)
为了避免这种情况,有没有比编写我自己的开始/结束包装器(内部使用ADL)并显式调用它们而不是std :: begin或ADLized begin更好的解决方案?
namespace my {
template<class T>
auto begin(T &c) // …Run Code Online (Sandbox Code Playgroud) 我正在尝试Sean Parent在GoingNative 2013上的演讲中提出的代码 - "继承是邪恶的基础".(最后一张幻灯片的代码可在https://gist.github.com/berkus/7041546获得
我试图自己实现相同的目标,但我无法理解为什么下面的代码不会按照我的预期行事.
#include <boost/smart_ptr.hpp>
#include <iostream>
#include <ostream>
template <typename T>
void draw(const T& t, std::ostream& out)
{
std::cout << "Template version" << '\n';
out << t << '\n';
}
class object_t
{
public:
template <typename T>
explicit object_t (T rhs) : self(new model<T>(rhs)) {};
friend void draw(const object_t& obj, std::ostream& out)
{
obj.self->draw(out);
}
private:
struct concept_t
{
virtual ~concept_t() {};
virtual void draw(std::ostream&) const = 0;
};
template <typename T>
struct model …Run Code Online (Sandbox Code Playgroud) c++ inheritance templates language-lawyer argument-dependent-lookup
我有以下代码:
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <conio.h>
#include <cstring>
#include <iomanip>
void swap(long a, long b)
{
long temp;
temp=a;
a=b;
b=temp;
}
int _tmain(int argc, _TCHAR* argv[])
{
int x = 5, y = 3;
cout << x ;
cout << y << endl;
swap(x, y);
cout << x ;
cout << y << endl;
getch();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该程序给出了输出:
5 3
3 5
Run Code Online (Sandbox Code Playgroud)
该程序实际上交换价值!这是为什么?这些参数swap()不是指针或引用.
(我正在使用VS 2005)
我在一些生产代码中遇到问题,我将其最小化到以下测试用例:
template<typename T>
void intermediate(T t)
{
func(t); // line 4 ("func not declared in this scope")
}
namespace ns {
struct type {};
}
void func(ns::type const & p); // line 11 ("declared here, later")
void foo(ns::type exit_node)
{
intermediate(exit_node); // line 15 ("required from here")
}
Run Code Online (Sandbox Code Playgroud)
GCC 4.5汇编了这个罚款.有和没有-std=c++11,4.7和4.9产生如下消息:
test.cpp: In instantiation of ‘void intermediate(T) [with T = ns::type]’:
test.cpp:15:27: required from here
test.cpp:4:5: error: ‘func’ was not declared in this scope, and no declarations were found …Run Code Online (Sandbox Code Playgroud) 为了优雅,封装和利用ADL(Argument Dependent Lookup)在函数参数的命名空间内定义一个函数是很常见的.
假设我在不同的命名空间中有两个库.有三种情况1)一个是我控制的库的一部分,另一个是第三方(例如Boost),或者2)我控制两者,或者3)我控制没有(只写"胶水"代码).
我有这样的事情,
namespace ns_A{
struct A{...}; // something that looks like iostream
}
namespace ns_B{
struct B{...};
}
Run Code Online (Sandbox Code Playgroud)
我想将"流"B流入A,最佳选择是什么
namespace ???{ // what is more correct ns_A, or ns_B?
A& operator<<(A& a, B const& b){...}
}
Run Code Online (Sandbox Code Playgroud)
或者我应该把它放在两个名称空间中?
namespace ns_B{
A& operator<<(A& a, B const& b){...}
}
namespace ns_A{
using ns_B::operator<<;
}
Run Code Online (Sandbox Code Playgroud)
哪个是定义像这样的二进制函数的最佳命名空间?
(C++ 11的命名空间内联是否会改变任何建议?)
(我使用这个例子operator<<是因为,在其他条件相同的情况下,直觉上看起来更好namespace ns_B.)
编辑:这是我可以找到的关于名称空间实际使用的最完整的指南和参考 https://www.google.com/amp/s/akrzemi1.wordpress.com/2016/01/16/a-customizable-framework/安培/
考虑这个代码示例
template <typename T> struct S { T t; };
template <class T> void foo(const S<T> &v)
{
bar(v.t);
}
namespace N
{
struct A {};
}
void bar(const N::A &a) {}
int main()
{
S<N::A> a;
foo(a);
}
Run Code Online (Sandbox Code Playgroud)
代码无法在GCC和Clang中编译,因为常规查找和ADL都无法解析bar来自的调用foo.这是完全可以预期的,因为bar调用的关联命名空间列表就是这样N.不包括全局命名空间,找不到全局命名空间bar.一切都应该如此.
但是,如果我将其更改为
template <typename T> struct S { T t; };
template <class T> void foo(const S<T> &v)
{
+v.t;
}
namespace N
{
struct A {};
}
void operator +(const …Run Code Online (Sandbox Code Playgroud) c++ gcc operator-overloading language-lawyer argument-dependent-lookup
为什么发明了依赖于参数的查找(ADL)?是这样我们可以写cout << stuff而不是std::operator<<(cout, stuff)?如果是这种情况,为什么ADL不限于运营商而不是所有功能?
如果C++有其他方法来执行内置和用户定义类型的通用输出,例如类型安全的printf可变参数模板,是否可以防止引入ADL ?
考虑重载加法运算的遗留类模板+=和+
template<class T>
class X
{
public:
X() = default;
/* implicict */ X(T v): val(v) {}
X<T>& operator+=(X<T> const& rhs) { val += rhs.val; return *this; }
X<T> operator+ (X<T> const& rhs) const { return X<T>(*this) += rhs; }
private:
T val;
};
Run Code Online (Sandbox Code Playgroud)
在代码审查时,观察到它+是可实现的+=,为什么不使它成为非成员(并保证左右参数的对称性)?
template<class T>
class X
{
public:
X() = default;
/* implicit */ X(T v): val(v) {}
X<T>& operator+=(X<T> const& rhs) { val += rhs.val; return *this; }
private: …Run Code Online (Sandbox Code Playgroud) c++ operator-overloading implicit-conversion argument-dependent-lookup non-member-functions
我花了一些时间试图意识到为什么我的代码不能编译,我已经意识到在C++ Argument Dependent Lookup中使用模板typename参数来确定名称查找范围.
#include <string>
#include <functional>
namespace myns {
template<typename T>
struct X
{};
template<typename T>
auto ref(T) -> void
{}
} // namespace myns
auto main() -> int
{
ref(myns::X<int>{});
ref(myns::X<std::string>{}); // error: call to 'ref' is ambiguous
}
Run Code Online (Sandbox Code Playgroud)
所以前面的ref调用编译,因为myns::X<int>只myns::ref考虑,而后者不编译,因为它发现myns::ref()以及std::ref
我的问题是这有用吗?我为什么需要这个?你有什么想法,例子吗?现在我只能看到上面例子中的缺点,它会引入不必要的歧义.
我有一个与此问题非常相似的问题.
简而言之,我有一个magic方法,noexcept如果是另一种方法noexcept.
奇怪的是,这个"另一个方法"有两个重载,编译器选择第二个重载来确定magic noexcept-ness.
但是,当magic稍后调用时,会调用第一个重载,但是noexcept-ness magic仍然保持不变!
这是wandbox 链接
据我所知:
noexcept(magic(dummy2{})) 电话noexcept(noexcept(adl_caller(...)) 这可以追溯到adl_caller(..., priority_tag<0>) noexcept因为user_method(dummy2)此时编译器不知道.然而,相当公平,如何user_method(dummy2)称为3行以上?这是标准的意图吗?
对不起,如果我不够清楚的话.
#include <iostream>
template <unsigned N> struct priority_tag : priority_tag<N - 1> {};
template <> struct priority_tag<0> {};
template <typename T>
auto adl_caller(T t, priority_tag<1>) noexcept(noexcept(user_method(t)))
-> decltype(user_method(t)) {
std::cout << "first adl_caller overload" << std::endl;
user_method(t);
}
// …Run Code Online (Sandbox Code Playgroud) c++ ×10
templates ×4
c++11 ×3
gcc ×1
history ×1
inheritance ×1
name-lookup ×1
noexcept ×1
swap ×1