我刚注意到一个带有重载决策的奇怪行为.
假设我有以下方法:
public static void DoSomething<T>(IEnumerable<T> items)
{
// Whatever
// For debugging
Console.WriteLine("DoSomething<T>(IEnumerable<T> items)");
}
Run Code Online (Sandbox Code Playgroud)
现在,我知道通常会使用少量显式参数调用此方法,因此为方便起见,我添加了此重载:
public static void DoSomething<T>(params T[] items)
{
// Whatever
// For debugging
Console.WriteLine("DoSomething<T>(params T[] items)");
}
Run Code Online (Sandbox Code Playgroud)
现在我尝试调用这些方法:
var items = new List<string> { "foo", "bar" };
DoSomething(items);
DoSomething("foo", "bar");
Run Code Online (Sandbox Code Playgroud)
但在这两种情况下,params都会调用重载.我希望IEnumerable<T>在a的情况下调用重载List<T>,因为它似乎是一个更好的匹配(至少对我而言).
这种行为是否正常?谁能解释一下呢?我在MSDN文档中找不到任何关于它的明确信息......这里涉及的重载决策规则是什么?
c# generics type-inference params-keyword overload-resolution
如何为函数调用转储候选函数(或可行函数或最佳可行函数)?
我知道g ++提供了转储类层次结构的选项.(事实上,Visual Studio 2010提供了类似的选项,但它没有文档.我记得读过一些关于它的内容 - 也许是在VC++团队博客中 - 但我不记得清楚了.)
最近,我一直在阅读关于C++ 0x草案中的重载解析,这让我很尴尬.
是否有任何编译器提供转储候选函数,可行函数或最佳可行函数的选项?
注意:重载决策场景中的候选函数与编译器错误中的候选函数不同.超载解决方案中的候选/可行/最佳可行功能具有其自身的含义.我知道他们在重载决策中有三个阶段:找到候选函数; 找到可行的功能; 找到最好的可行功能.通常,最好的可行功能只是一个候选者; 否则,电话是不明确的.每个阶段都有自己的规则.
(标题中的"用户定义"是指C#标准的加法和减法,TimeSpan而DateTime不是C#标准的一部分.它们在BCL中定义.)
在可空TimeSpan和DateTime值上玩弄提升的运算符,我写了下面的代码.请注意,这个框架提供了不同的操作TimeSpan和DateTime.
有一个对称(和可交换)的加法,你接收两个TimeSpan并返回总和TimeSpan.这个加法的"逆"是减去两个,TimeSpan产生一个TimeSpan.
然后是另一种加法,非对称,你拿一个DateTime(左操作数)和一个TimeSpan(右操作数)来产生一个DateTime.由于此操作的不对称性,它有两种"反转"类型:一种是DateTime从中减去两种以获得TimeSpan差异,另一种是从中DateTime减去一种并从中减去一种TimeSpan以产生结果DateTime.
static void Main()
{
DateTime? n_dt = new DateTime(2012, 12, 25);
TimeSpan? n_ts = TimeSpan.FromDays(62.0);
var a = n_dt + n_ts; // OK
var b = n_ts + n_ts; // OK
var c = null + n_dt; // OK, string …Run Code Online (Sandbox Code Playgroud) c# null operator-overloading lifted-operators overload-resolution
==委托类型的两个表达式之间的重载解析的准确规则是什么?
请考虑以下代码(using System;需要的地方):
static class ProgramA
{
static void TargetMethod(object obj)
{
}
static void Main()
{
Action<object> instance1 = TargetMethod;
Action<object> instance2 = TargetMethod;
Action<string> a1 = instance1;
Action<Uri> a2 = instance2;
Console.WriteLine((object)a1 == (object)a2);
Console.WriteLine((Delegate)a1 == (Delegate)a2);
Console.WriteLine((Action<object>)a1 == (Action<object>)a2);
Console.WriteLine(a1 == a2); // warning CS0253: Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'System.Action<string>'
}
}
Run Code Online (Sandbox Code Playgroud)
说明:
instance1并且instance2是同一运行时类型的两个独立实例,泛型Action<in T>是逆变的 …
Visual C++ 2012.代码.我认为它应该编译; 编者恭敬地不同意.我把我的责备缩小到:
struct B { };
void foo(B* b, signed int si) { } // Overload 1
void foo(B const* b, unsigned int ui) { } // Overload 2
int main()
{
B b;
unsigned int ui;
foo(&b, ui);
}
Run Code Online (Sandbox Code Playgroud)
所以我们有两个重载决策候选者.对于第一个重载,第一个参数完全匹配,第二个参数需要整数转换(unsigned to signed).对于第二个重载,第二个参数完全匹配,第一个参数需要cv-adjustment(因为&b是指向非const的指针).
现在,似乎这应该是完全明确的.对于Overload 1,第一个参数是标准关于重载决策的部分定义的"精确匹配",但第二个参数是"转换".对于Overload 2,两个参数都是"Exact Matches"(资格转换与身份相同).因此(我显然不完美的推理),应该选择Overload 2,没有歧义.但是:
a.cpp(12): error C2666: 'foo' : 2 overloads have similar conversions
a.cpp(6): could be 'void foo(const B *,unsigned int)'
a.cpp(5): or 'void foo(B *,int)'
while trying to match the …Run Code Online (Sandbox Code Playgroud) 我们如何能实现,给定一个类型可变参数模板T和类型列表E1,E2,... EÑ,确定名单,从转换的类型T为该类型,根据重载解析,最好的?
void如果不存在最佳转换,则应该是输出 - 换句话说,当存在歧义或者T无法转换为列表中的任何类型时.
请注意,这意味着我们的模板应该是SFINAE友好的,即在没有最佳转换时不会出现硬错误.
以下static_asserts应该成功:
static_assert( std::is_same< best<int, long, short>, void >{}, "" );
static_assert( std::is_same< best<int, long, std::string>, long >{}, "" );
static_assert( std::is_same< best<int>, void >{}, "" );
Run Code Online (Sandbox Code Playgroud)
(假设,为简单起见,这best是一个引用实际模板的别名模板)
这个案例未指明:
static_assert( std::is_same< best<int, int, int>, ???>{}, "" );
Run Code Online (Sandbox Code Playgroud)
无论是void或者int应该是可以接受在这里.(如果选择后者,那么我们仍然可以在包装器模板中检查结果类型是否在列表中包含两次,如果是,则输出void相反).
c++ type-conversion overload-resolution variadic-templates c++14
为什么以下代码不能编译,当我在A类中的构造函数之前删除显式关键字时,它编译?
使用Visual Studio 2013:
enum E { e1_0, e1_1 };
template<typename T>
struct A
{
A() {}
explicit A(unsigned long) {}
A(T) {}
};
struct B
{
B() {}
B(E) {}
};
void F(B) {};
void F(A<short>) {};
void test()
{
F(e1_0);
}
Run Code Online (Sandbox Code Playgroud)
错误:
1>------ Build started: Project: exp_construct_test, Configuration: Debug Win32 ------
1> exp_construct_test.cpp
1>e:\exp_construct_test\exp_construct_test.cpp(23): error C2668: 'F' : ambiguous call to overloaded function
1> e:\exp_construct_test\exp_construct_test.cpp(19): could be 'void F(A<short>)'
1> e:\exp_construct_test\exp_construct_test.cpp(18): or 'void F(B)'
1> while trying to …Run Code Online (Sandbox Code Playgroud) 关于下面提到的编译器错误以及如何解决它,有很多问题/解答,但是这里的问题是询问一些见解,为什么在这种情况下需要这样做。
为什么使用另一个引用的项目B的方法的重载的项目A(在其中一个重载的签名中使用项目C的对象),就要求您引用项目A的项目C,即使您从不使用来自该对象的对象也是如此。项目C?
我想这必须与使用哪种重载有关,但我想了解其背后的概念。
这是一个例子:
将每个类放在自己的程序集中。
//Put into Assembly C
public class C {}
//Put into assembly B, reference C
public class B
{
public static void Test(string param) //Simple method with one string parameter
{
}
public static void Test(C param) //Overload which uses type of assembly C
{
}
}
//Call placed in method of assembly A which uses and references only assembly B, but not C
B.Test("TestString"); // fails to compile, CS0012
Run Code Online (Sandbox Code Playgroud)
CS0012类型'C'在未引用的程序集中定义。您必须添加对程序集'C,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = …
.net c# .net-assembly overload-resolution assembly-references
考虑以下程序:
using System;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
var stringTask = Task.FromResult("sample");
stringTask.TeeAsync(st => Task.CompletedTask).Wait();
}
}
public static class FunctionalExtensions
{
public static async Task<T> TeeAsync<T>(this T source, Func<T, Task> asyncAction)
{
await Task.Delay(0); // todo: do something with source
return source;
}
public static async Task<T> TeeAsync<T>(this Task<T> asyncSource, Func<T, Task> asyncAction)
{
var source = await asyncSource;
await Task.Delay(0); // todo: do something with source
return source;
}
}
Run Code Online (Sandbox Code Playgroud)
第9行上的编译器错误因为而TeeAsync …
我有这段代码可以在GCC 9.1中正常工作:
#include <type_traits>
template< typename T >
class A
{
protected:
T value;
public:
template< typename U,
typename...,
typename = std::enable_if_t< std::is_fundamental< U >::value > >
A& operator=(U v)
{
value = v;
return *this;
}
};
template< typename T >
class B : public A<T>
{
public:
using A<T>::operator=;
template< typename U,
typename...,
typename = std::enable_if_t< ! std::is_fundamental< U >::value > >
B& operator=(U v)
{
this->value = v;
return *this;
}
};
int main()
{
B<int> obj; …Run Code Online (Sandbox Code Playgroud) c# ×5
c++ ×5
.net ×2
c++14 ×2
generics ×2
visual-c++ ×2
c++11 ×1
compiler-bug ×1
constructor ×1
delegates ×1
name-hiding ×1
null ×1
overloading ×1