特别是在linux上使用g ++,有没有办法确定为特定语句选择了哪个重载或模板函数?
更具体地说,我不认为我必须知道所有可能的选择,这些选择可能来自各种库的头文件.即使我这样做,我也不认为我可以修改相关代码.
以下程序无法编译,因为在出错的行中,编译器选择使用单个T参数作为分辨率的方法,该方法失败,因为List<T>它不符合单个的通用约束T.编译器无法识别可以使用的其他方法.如果我删除单一T方法,编译器将正确地找到许多对象的方法.
我读过有关泛型方法的高分辨率双向博客文章,一个来自JonSkeet 这里和另一名来自埃里克利珀这里,但我无法找到一个解释或解决我的问题的一种方式.
显然,使用两个具有不同名称的方法会起作用,但我喜欢这样一个事实:对于这些情况,您只有一种方法.
namespace Test
{
using System.Collections.Generic;
public interface SomeInterface { }
public class SomeImplementation : SomeInterface { }
public static class ExtensionMethods
{
// comment out this line, to make the compiler chose the right method on the line that throws an error below
public static void Method<T>(this T parameter) where T : SomeInterface { }
public static void Method<T>(this IEnumerable<T> parameter) where T : SomeInterface …Run Code Online (Sandbox Code Playgroud) 代码示例:
interface IFoo { }
class FooImpl : IFoo { }
static void Bar<T>(IEnumerable<T> value)
where T : IFoo
{
}
static void Bar<T>(T source)
where T : IFoo
{
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释,为什么这个方法调用:
var value = new FooImpl[0];
Bar(value);
Run Code Online (Sandbox Code Playgroud)
目标Bar<T>(T source)(因此,不编译)?
在解决重载时,编译器是否会考虑类型参数约束?
UPD.
避免与数组混淆.任何实现都会发生这种情况IEnumerable<T>,例如:
var value = new List<FooImpl>();
Run Code Online (Sandbox Code Playgroud)
UPD 2.
@ ken2k提到了协方差.但是,让我们忘掉FooImpl.这个:
var value = new List<IFoo>();
Bar(value);
Run Code Online (Sandbox Code Playgroud)
产生相同的错误.
我敢肯定,之间的隐式转换List<IFoo>和IEnumerable<IFoo>存在,因为我可以很容易地写出这样的事情:
static void SomeMethod(IEnumerable<IFoo> sequence) {}
Run Code Online (Sandbox Code Playgroud)
并传入value其中: …
这是关于模板函数中的依赖名称查找,例如:
template<class T>
void foo(T const &t)
{
::func(t);
}
Run Code Online (Sandbox Code Playgroud)
在这段代码中,func是一个依赖名称,因为它有一个依赖于类型的表达式作为函数调用的参数。在 C++11 中func,[temp.dep.candidate]/1 涵盖了查找:
对于依赖于模板参数的函数调用,使用通常的查找规则(3.4.1、3.4.2、3.4.3)找到候选函数,除了:
- 对于使用非限定名称查找 (3.4.1) 或限定名称查找 (3.4.3) 的查找部分,只能找到来自模板定义上下文的函数声明。
- 对于使用关联命名空间(3.4.2)的查找部分,只找到在模板定义上下文或模板实例化上下文中找到的函数声明。
[注意:3.4.1 是“普通”非限定 id 查找,3.4.2 是函数名称的非限定 id 查找,也就是。ADL 和 3.4.3 是qualified-id 查找]。
然而,在 C++14 (N3936) 中,关于qualified-id查找的部分被删除了:
对于后缀表达式是依赖名称的函数调用,使用通常的查找规则 (3.4.1, 3.4.2) 找到候选函数,除了:
- 对于使用非限定名称查找 (3.4.1) 的查找部分,只能找到来自模板定义上下文的函数声明。
- 对于使用关联命名空间(3.4.2)的查找部分,只找到在模板定义上下文或模板实例化上下文中找到的函数声明。
假设此更改是故意进行的;哪些子句现在涵盖了为后缀表达式是依赖名称和限定 ID 的函数调用寻找候选函数?
(背景:我正在寻找确认限定名称查找仍然只在模板定义上下文中查找,而不是在实例化上下文中查找)。
我对标准转换序列术语有误解。我遇到了以下引用N3797 §8.5.3/5 [dcl.init.ref]:
— 如果初始化表达式
— 是 xvalue(但不是位域)、类纯右值、数组纯右值或函数左值,并且“ cv1 T1”与“ cv2 T2”引用兼容,或
— 具有类类型(即,T2 是类类型),其中 T1 与 T2 没有引用相关,并且可以转换为“ cv3 T3”类型的 xvalue、类纯右值或函数左值,其中“ cv1 T1” ”与“ cv3 T3”(见13.3.1.6)引用兼容,
[..] 在第二种情况下,如果引用是右值引用并且用户定义的转换序列的第二个标准转换序列包括左值到右值的转换,则程序格式错误。
这里的第二个标准转换序列是什么?我认为有一个标准转换序列,包括所有必要的标准转换(用户定义的和隐式的)。
c++ language-lawyer overload-resolution implicit-conversion c++11
这并不像看起来那么微不足道.这是这个问题的后续行动.
假设我有一个带有属性的Windows窗体用户控件:
// using System.ComponentModel;
[DefaultValue(null)]
public object DataSource { … }
Run Code Online (Sandbox Code Playgroud)
如果我把它翻译成VB.NET,我会试试这个:
'Imports System.ComponentModel
<DefaultValue(Nothing)>
Public Property DataSource As Object
…
End Property
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为编译器在选择构造函数的正确重载时DefaultValueAttribute遇到问题:
重载决策失败,因为
New这些参数的特定访问权限不是最具体的:
Public Sub New(value As Boolean):不是最具体的.Public Sub New(value As Byte):不是最具体的.Public Sub New(value As Char):不是最具体的.
我很确定这是因为Nothing在VB.NET中不仅意味着"空引用"(null在C#中),而且还是"参数类型的默认值"(default(T)在C#中).由于这种歧义,每个构造函数重载都是潜在的匹配.
<DefaultValue(CObj(Nothing))> 也不会起作用,因为它不是一个恒定的值.
究竟是如何做我在VB.NET写的吗?
PS: <DefaultValue(GetType(Object), Nothing)>是一个选项,但它可以解决问题.如果有任何方法可以使用与DefaultValueAttributeC#版本相同的构造函数,我真的很感兴趣.
我想ostream&通过查看是否提供了重载来测试类是否可以流式传输operator<<.根据这些 帖子,我尝试使用C++ 11编写另一个版本.这是我的尝试:
#include <iostream>
#include <type_traits>
namespace TEST{
class NotDefined{};
template<typename T>
NotDefined& operator << (::std::ostream&, const T&);
template <typename T>
struct StreamInsertionExists {
static std::ostream &s;
static T const &t;
enum { value = std::is_same<decltype(s << t), NotDefined>() };
};
}
struct A{
int val;
friend ::std::ostream& operator<<(::std::ostream&, const A&);
};
::std::ostream& operator<<(::std::ostream& os, const A& a)
{
os << a.val;
return os;
}
struct B{};
int main() {
std::cout << TEST::StreamInsertionExists<A>::value …Run Code Online (Sandbox Code Playgroud) 在 .NET 中,如果有一个具有方法Foo<T>(T t)(无约束)和方法 Foo(string s) 的类,则调用会Foo("test")调用Foo接受string. 这一切都很好,除非string重载是一个扩展方法,在这种情况下总是调用泛型版本。是否有解决此问题的方法,还是我不走运?
传递std::min给函数不会编译.我将libcpp声明复制std::min到我的源文件中并且它可以工作.
std版本有什么问题?clang和gcc也是如此.在godbolt上测试:https://godbolt.org/g/zwRqUA
#include <thread>
#include <algorithm>
namespace mystd {
// declaration copied verbatim from std::min (libcpp 4.0)
template <class _Tp> inline constexpr const _Tp&
mymin(const _Tp& __a, const _Tp& __b)
{
return std::min(__a, __b);
}
}
int main()
{
std::thread thr1(std::min<int>, 2, 3); // compile error
std::thread thr2(mystd::mymin<int>, 2, 3); // works
return 0;
}
Run Code Online (Sandbox Code Playgroud)
clang和gcc的错误:
[x86-64 clang 5.0.0 #1] error: no matching constructor for initialization of 'std::thread'
[x86-64 gcc 7.2 #1] error: no …Run Code Online (Sandbox Code Playgroud) #include <iostream>
#include <vector>
int main()
{
auto v1 = std::vector<std::size_t>(std::size_t{8});
std::cout << v1.size() << std::endl;
auto v2 = std::vector<std::size_t>{std::size_t{8}};
std::cout << v2.size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
代码输出:
8
1
Run Code Online (Sandbox Code Playgroud)
我知道这是C ++中的一个众所周知的问题,因为:
std::vector<std::size_t>(std::size_t{8}) 来电
explicit vector(size_type count) 而
std::vector<std::size_t>{std::size_t{8}} 来电
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator())。
出乎我的意料:
为什么第二次调用不触发针对重载解析度歧义的编译时错误?
在另一个相关问题中,一段类似的代码确实触发了歧义错误。
c++ ×6
c# ×4
templates ×4
c++11 ×3
generics ×3
ambiguous ×1
c#-to-vb.net ×1
c++14 ×1
overloading ×1
vb.net ×1