假设,我想开发一个通用库,它应该可以用于类似数字的类型,包括双重和用户定义的类型.我现在面临的问题是,我不知道如何编写函数模板的返回类型,就像这样:
template<class T>
auto transmogrify(T x)
-> ???
{
using std::abs;
return abs(x)+2.0;
}
Run Code Online (Sandbox Code Playgroud)
using声明使这个函数模板的主体适用于原始类型,因为它们没有关联的命名空间(因此没有ADL).但是我希望transmogrify使用专门的abs函数,以防用户定义类型的作者提供自己的abs函数.我不能简单地使用
-> decltype( abs(x)+2.0 )
Run Code Online (Sandbox Code Playgroud)
因为这不适用于比赛,因为std :: abs不在范围内(据我所知).但写作
-> decltype( std::abs(x)+2.0 )
Run Code Online (Sandbox Code Playgroud)
会禁用ADL.但禁用ADL不是一种选择.此外,专用abs函数返回的值可能不是T类型,而是某些其他类型.
关于如何解决返回类型问题的任何想法,同时(a)保持ADL和(b)回退到某些默认函数(如本例中的std :: abs),对于不提供专用abs的类型.
c++ generic-programming decltype argument-dependent-lookup c++11
#include <iostream>
namespace Foo
{
class Baz { };
std::ostream& operator<< ( std::ostream& ostream , const Baz& baz )
{
return ostream << "operator<<\n";
}
}
int main()
{
std::cout << Foo::Baz();
}
Run Code Online (Sandbox Code Playgroud)
我operator<<在Foo命名空间中定义了一个.为什么可以从全球范围调用它?
情况是某些成员函数bar::Bar::frobnicate想要利用ADL从具有相同名称的函数内的某个未知命名空间中查找函数.但是,它只找到自己的名字.
(请注意,实际上,这Bar是一个Foo不可知的模板;这只是可重现的,最小的测试用例)
namespace foo {
struct Foo {};
void frobnicate(Foo const &) {}
}
namespace bar {
struct Bar {
void frobnicate() {
foo::Foo foo;
frobnicate(foo); // <-- error
}
};
}
int main () {
bar::Bar x;
x.frobnicate();
frobnicate(foo::Foo());
}
Run Code Online (Sandbox Code Playgroud)
结果是:
test.cc: In member function ‘void bar::Bar::frobnicate()’:
test.cc:10:31: error: no matching function for call to ‘bar::Bar::frobnicate(foo::Foo&)’
test.cc:10:31: note: candidate is:
test.cc:8:18: note: void bar::Bar::frobnicate()
test.cc:8:18: note: candidate expects 0 arguments, …Run Code Online (Sandbox Code Playgroud) c++ interface argument-dependent-lookup non-member-functions
我已经研究过并发现当你想为cout重载输出流操作符时,那么正确的方法是这样做:
std::ostream& operator<<(std::ostream& os, const T& obj)
Run Code Online (Sandbox Code Playgroud)
这个函数必须在类之外定义,因为这里发生的是操作符<<实际上是ostream中定义的友元函数,你正在使用它.但是,问题是,这个函数究竟是如何在ostream中定义的?由于此函数需要2个参数,而第二个参数是用户定义的,因此他们无法猜出将要发生什么.
特定类的重载应如下所示:
std::ostream& operator<<(std::ostream& os, const MyClass& obj)
Run Code Online (Sandbox Code Playgroud)
编译器/库如何为第二个参数采用泛型定义,特别是因为在C++中没有泛型类(如Java中的Object)这样的东西?
该标准的引用表示赞赏.
#include <iostream>
namespace X {
class A {};
}
template <typename T>
inline T const& max(T const& a, T const& b, T const& c)
{
return max(max(a, b), c);
}
inline X::A const& max(X::A const& a, X::A const& b)
{
std::cout << "non-template" << '\n';
return a;
}
int main()
{
X::A a, b, c;
max(a, b, c);
}
namespace X {
template <typename T>
inline T const& max(T const& a, T const& b)
{
std::cout << "template" << …Run Code Online (Sandbox Code Playgroud) c++ templates language-lawyer argument-dependent-lookup c++11
我试图了解为什么以下代码无法编译:
namespace ns {
struct S {};
}
namespace alleq {
inline bool
operator==(const ns::S &, const ns::S &)
{
return true;
}
}
namespace ns {
using namespace alleq;
// using alleq::operator==; // Works if you uncomment this
}
ns::S a;
void
f()
{
::ns::operator==(a, a); // OK
a == a; // Error: no match for 'operator=='
}
Run Code Online (Sandbox Code Playgroud)
函数的第一行f确实可以编译,这使我相信命名空间ns包含一个function operator==。但是,当我比较type的两个值时ns::S,operator==找不到此函数。相比之下,using声明确实可以按预期工作,并且允许ADL f查找第二行ns::operator==。
我怀疑原因与使用指令应该使符号看起来像它出现在全局名称空间中有关::(因为这是名称空间alleq …
以下简化示例编译gcc并且Visual Studio,但是失败了clang!?
namespace N
{
struct A {};
template <typename T>
double operator+ (T a, double d) {return d;}
template <typename T>
double operator+ (double d, T a) {return d;}
}
void test()
{
N::A a;
double x;
double y = a + x;
double z = x + a;
}
Run Code Online (Sandbox Code Playgroud)
在我看来,ADL可以找到模板operator+名称空间N.
为什么不clang同意?它是clang其他编译器中的错误吗?
这是来自clang 3.5.1的编译错误(在coliru上测试过),我不明白这里有什么问题......
10 : error: overloaded 'operator+' must have at least one parameter …Run Code Online (Sandbox Code Playgroud) c++ namespaces operator-overloading clang argument-dependent-lookup
阅读了一篇很棒的文章真实的故事:高效的包装我试着自己实现元组作为练习:
#include <type_traits>
#include <utility>
#include <functional>
template< std::size_t I, typename T >
struct tuple_leaf { T value; };
template< std::size_t I, typename T >
T & get(tuple_leaf< I, T > & leaf)
{ return leaf.value; }
template< typename Is, typename ...Ts >
struct tuple_base;
template< std::size_t ...Is, typename ...Ts >
struct tuple_base< std::index_sequence< Is... >, Ts... >
: tuple_leaf< Is, Ts >...
{
using tuple_base_t = tuple_base;
template< typename ...Args, typename = std::enable_if_t< (sizeof...(Ts) == sizeof...(Args)) > …Run Code Online (Sandbox Code Playgroud) 根据标准,在类中声明和定义的友元函数只能由ADL查找.所以,我认为以下代码应该编译.
template<int M>
struct test{
template<int N = 0>
friend void foo(test){}
};
int main(){
test<2> t;
foo(t);// compile
foo<1>(t);// error
}
Run Code Online (Sandbox Code Playgroud)
但是,gcc给出以下错误:
main.cpp: In function 'int main()':
main.cpp:10:5: error: 'foo' was not declared in this scope
foo<1>(t);
^~~
Run Code Online (Sandbox Code Playgroud)
然后,我有三个问题.
template<int N> foo按照标准找到?foo发现foo<1>不是?foo外部之外还有解决方法吗?c++ friend-function function-templates argument-dependent-lookup
我正在尝试为另一个命名空间中定义的类型T定义一个等于运算符,然后使用相等运算符optional<T>.在clang(Apple LLVM 9.1.0)上,此代码:
namespace nsp {
struct Foo {
};
}
bool operator==(const nsp::Foo& a, const nsp::Foo& b);
void foo() {
optional<nsp::Foo> a = none;
optional<nsp::Foo> b = none;
if (a == b)
;
}
Run Code Online (Sandbox Code Playgroud)
导致错误:
/usr/local/include/boost/optional/detail/optional_relops.hpp:29:34: error: invalid operands to binary expression ('const nsp::Foo' and 'const nsp::Foo')
{ return bool(x) && bool(y) ? *x == *y : bool(x) == bool(y); }
~~ ^ ~~
MWE.cpp:40:19: note: in instantiation of function template specialization 'boost::operator==<what3words::engine::nsp::Foo>' requested here
if (a …Run Code Online (Sandbox Code Playgroud)