在这个问题的回答中:用双花括号初始化向量<string>
结果表明
vector<string> v = {{"a", "b"}};
Run Code Online (Sandbox Code Playgroud)
将使用一个元素std::vector调用构造函数。因此向量中的第一个(也是唯一的)元素将由 构造。这会导致未定义的行为,但这超出了这里的重点。initializer_list{"a", "b"}
我发现的是
std::vector<int> v = {{2, 3}};
Run Code Online (Sandbox Code Playgroud)
将std::vector使用两个元素initializer_list中的一个调用构造函数。
为什么会出现这种行为差异的原因呢?
我试图了解 noexcept 功能。我知道这可能会令人困惑,但除此之外,如果可能的话,不能从调用函数中推导出来。
这是这种情况的非工作示例,
void f(){}
void f() noexcept{} // not allowed in c++
void g(){f();} // should call f
void h() noexcept{f();} // should call f noexcept
int main(){
g();
h();
}
Run Code Online (Sandbox Code Playgroud)
如果调用函数 ( h) 中没有 try/catch 块,那么编译器可以推断出有人对调用特定的 f 感兴趣。
此模式是否以其他解决方法形式使用?
我所能想象的就是这样的东西,但它不是很通用:
template<bool NE> void F() noexcept(NE);
template<>
void F<true>() noexcept(true){}
template<>
void F<false>() noexcept(false){}
void g(){F<noexcept(g)>();} // calls F<false>
void h() noexcept{F<noexcept(h)>();} // call F<true>
Run Code Online (Sandbox Code Playgroud)
有些人可能想知道为什么这会有意义。我的逻辑是,C++ 允许重载const函数参数和成员函数。
const例如,成员函数更喜欢调用const成员重载。
我认为noexcept函数调用noexcept …
考虑这两个扩展方法,它们只是从任何类型T1到的简单映射T2,加上一个重载以流畅地映射到Task<T>:
public static class Ext {
public static T2 Map<T1, T2>(this T1 x, Func<T1, T2> f)
=> f(x);
public static async Task<T2> Map<T1, T2>(this Task<T1> x, Func<T1, T2> f)
=> (await x).Map(f);
}
Run Code Online (Sandbox Code Playgroud)
现在,当我使用第二个重载映射到引用类型时......
var a = Task
.FromResult("foo")
.Map(x => $"hello {x}"); // ERROR
var b = Task
.FromResult(1)
.Map(x => x.ToString()); // ERROR
Run Code Online (Sandbox Code Playgroud)
...我收到以下错误:
CS0121:以下方法或属性之间的调用不明确:“Ext.Map(T1, Func)”和“Ext.Map(Task, Func)”
映射到值类型工作正常:
var c = Task
.FromResult(1)
.Map(x => x + 1); // works
var …Run Code Online (Sandbox Code Playgroud) #include <iostream>
#define FUNC() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
void foo(char const*&& ) FUNC() // A
void foo(char const(&)[4]) FUNC() // B
int main()
{
foo("bar");
}
Run Code Online (Sandbox Code Playgroud)
当在第一个重载 (A) 的参数类型中使用右值引用时,clang current master 明确地选择重载 A 而不是 B。另一方面,GCC current master 抱怨歧义。
我很惊讶字符串文字是4char const的左值([expr.prim.literal]/1 , [lex.string]/6)应该更喜欢重载 A 上的数组到指针转换而不是身份转换过载 B.
如果没有右值引用,即void foo(char const*),GCC 和 clang 都拒绝调用不明确。这也是我不完全理解的事情,因为我会猜测仍然存在数组到指针的转换,因此[over.ics.rank]p3.2.1适用:
标准转换序列 S1 是比标准转换序列 S2 更好的转换序列,如果
- (3.2.1) S1是S2的真子序列(比较[over.ics.scs]定义的规范形式的转换序列,不包括任何左值转换;恒等转换序列被认为是任何非-身份转换序列),或者,如果不是,
在这两种情况下发生了什么?
以下程序:
#include <iostream>
struct A
{
A() { std::cout << "A()\n"; }
A(int) { std::cout << "A(int)\n"; }
};
struct C {
operator int() {
std::cout << "operator int\n";
return 42;
}
operator A() {
std::cout << "operator A\n";
return A();
}
};
int main() {
auto a = A{C{}};
};
Run Code Online (Sandbox Code Playgroud)
编译并在运行时打印:
operator A
A()
Run Code Online (Sandbox Code Playgroud)
请参阅Godbolt 链接。
这表明选择了 的移动构造函数A来执行初始化,C::operator A()并被调用以转换C为移动构造函数期望的类型。
或者,A::A(int)构造函数可能已被选中C::operator int()并被调用。但A::A(int)显然失去了重载分辨率。
为什么会发生这种情况?我无法在标准中看到任何解释为什么移动构造函数A赢得重载决议的规则。
(这个问题受到 …
在下面的程序中 structS提供了两个转换运算符: indouble和 in long long int。然后一个类型的对象S被传递给一个函数f,重载为floatand double:
struct S {
operator double() { return 3; }
operator long long int() { return 4; }
};
void f( double ) {}
void f( float ) {}
int main() {
S s;
f( s );
}
Run Code Online (Sandbox Code Playgroud)
MSVC 编译器可以正常接受程序,并选择f( double )重载。f然而,GCC 和 Clang 都发现, demo的调用存在歧义:https: //gcc.godbolt.org/z/5csd5dfYz
看来MSVC在这里是对的,因为转换:
operator long long int()->f( float )不是提升。这是错的吗? …
c++ overloading conversion-operator language-lawyer overload-resolution
在下面的程序中,struct B有两个用户定义的构造函数:一个来自int,另一个来自int&&(显然这不太实用)。并且 的对象B是从左值创建的,它应该明确选择第一个构造函数。thenstruct C是B通过 - 声明继承其构造函数而派生的using,并且 的对象C是从完全相同的左值创建的:
struct B {
B(int) {}
B(int&&) {}
};
int i = 1;
B b(i); //ok everywhere
struct C : B {
using B::B;
};
C c(i); //ok in Clang only
Run Code Online (Sandbox Code Playgroud)
MSVC 在最后一行打印出相当奇怪的错误:
source>(10): error C2668: 'B::B': ambiguous call to overloaded function
<source>(3): note: could be 'B::B(int &&)'
<source>(2): note: or 'B::B(int)'
<source>(10): note: while trying to match …Run Code Online (Sandbox Code Playgroud) 在下面的程序中,从其基类struct B继承已删除的构造函数,并且还定义了附加构造函数。然后创建一个对象:B(int)AB(int&&)BB b(1)
struct A {
A() {}
A(int) = delete;
};
struct B : A {
using A::A;
B(int&&) {}
};
int main() {
B b(1);
}
Run Code Online (Sandbox Code Playgroud)
如果构造函数B(int)和B(int&&)都直接在结果中定义,B则构造函数选择会产生歧义。在这个例子中,GCC 打印了一个
重载“B(int)”的调用不明确`
错误也是如此。
但 Clang 更喜欢在 中声明的构造函数B而不是从 继承的构造函数A。演示: https: //gcc.godbolt.org/z/dnErEenE5
这里是哪个编译器?
让我们创建柯里化函数。
template <typename TFunc, typename TArg>
class CurryT
{
public:
CurryT(const TFunc &func, const TArg &arg)
: func(func), arg(arg )
{}
template <typename... TArgs>
decltype(auto) operator()(TArgs ...args) const
{ return func(arg, args...); }
private:
TFunc func;
TArg arg ;
};
template <typename TFunc, typename TArg>
CurryT<decay_t<TFunc>, remove_cv_t<TArg>>
Curry(const TFunc &func, const TArg &arg)
{ return {func, arg}; }
Run Code Online (Sandbox Code Playgroud)
以及将函数解耦为单参数函数的函数:
// If single argument function (F(int)).
template <typename F>
static auto Decouple(const F &f, enable_if_t<is_invocable_v<F, int>> * = nullptr) …Run Code Online (Sandbox Code Playgroud) 我定义了两个版本的函数模板,名为compare:
#include <cstring>\n\nusing namespace std;\n\n// fist version\ntemplate <size_t N, size_t M>\nint compare(const char (&a)[N], const char (&b)[M]) {\n return strcmp(a, b);\n}\n\n// second version\ntemplate <typename T>\nint compare(const T &a, const T &b) {\n if (a < b) return -1;\n if (b < a) return 1;\n return 0;\n}\n\nint main() {\n const char *p1 = "dog", *p2 = "cat";\n compare(p1, p2); // call second version\n compare("dog", "cat"); // call second version?\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n在使用c++11std的CPP Primer(第5版)一书中,作者说compare(p1, p2)将调用第二版模板,因为没有办法将指针转换为对数组的引用。将 …