我最近接触过这个问题,答案可以概括为"这是一个非受限的背景".
具体来说,第一个说它是这样的东西,然后重定向到"细节"的标准,而第二个引用标准,这至少可以说是神秘的.
有人可以向凡人解释,比如我自己,什么是非受限的背景,什么时候发生,为什么会发生?
c++ templates template-argument-deduction argument-deduction
考虑
#include <iostream>
#include <type_traits>
template <class T, class ARG_T = T&>
T foo(ARG_T v){
return std::is_reference<decltype(v)>::value;
}
int main() {
int a = 1;
std::cout << foo<int>(a) << '\n';
std::cout << foo<int, int&>(a) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
我希望两种情况下的输出均为1。但在第一种情况下为0:与默认值class ARG_T = T而不是一致class ARG_T = T&。
我想念什么?
c++ templates function-templates template-argument-deduction argument-deduction
使用类模板参数推导我们可以写:
std::less Fn;
Run Code Online (Sandbox Code Playgroud)
但是,G ++ 8.2拒绝此代码:
#include <algorithm>
#include <vector>
#include <functional>
int main()
{
std::vector v= { 1, 3, 2, 7, 5, 4 };
std::sort(v.begin(),v.end(),std::greater());
}
Run Code Online (Sandbox Code Playgroud)
发出以下错误:
error: cannot deduce template arguments for 'greater' from ()
Run Code Online (Sandbox Code Playgroud)
Clang ++ 7.0和MSVC 15.8.0在没有警告的情况下编译它.哪个编译器是对的?
这是一个更复杂的问题,如果参数是一个重载函数,重载决策是如何工作的?
下面的代码编译没有任何问题:
void foo() {}
void foo(int) {}
void foo(double) {}
void foo(int, double) {}
// Uncommenting below line break compilation
//template<class T> void foo(T) {}
template<class X, class Y> void bar(void (*f)(X, Y))
{
f(X(), Y());
}
int main()
{
bar(foo);
}
Run Code Online (Sandbox Code Playgroud)
模板参数推导似乎不是一项具有挑战性的任务 - 只有一个函数foo()接受两个参数.但是,取消注释模板重载foo()(仍然只有一个参数)会破坏编译,没有明显的原因.使用gcc 5.x/6.x和clang 3.9编译失败.
可以通过重载决策/模板参数推导的规则来解释它还是应该被认为是那些编译器中的缺陷?
我对下面的模板行为感到困惑,它使用空尖括号(没有参数的模板)编译很好,因为从语法上讲,模板<>被保留以标记显式模板特化.
template <typename T> void add(T a, T b) { }
int main() {
add<>(10, 3); // compiles fine since both parameters are of same data type
add<>(10, 3.2); // Error: no matching function for call to add(int, double)
}
Run Code Online (Sandbox Code Playgroud)
在上面的例子中模板参数真的是可选的吗?
据我所知,SFINAE意味着替换失败不会导致编译错误,只是从可能的重载列表中删除原型.
我不明白:为什么这个SFINAE:
template <bool C, typename T = void> struct enable_if{};
template <typename T> struct enable_if<true, T> { typedef T type; };
Run Code Online (Sandbox Code Playgroud)
但这不是吗?
template <bool C> struct assert;
template <> struct assert<true>{};
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这里的基本逻辑是相同的.这个问题来自对这个答案的评论.
在这个Q&A中,我编写了一个小包装类,它提供了对范围的反向迭代器访问,依赖于类模板的c ++ 1z语言特征模板参数推导(p0091r3,p0512r0)
#include <iostream>
#include <iterator>
#include <vector>
template<class Rng>
class Reverse
{
Rng const& rng;
public:
Reverse(Rng const& r) noexcept
:
rng(r)
{}
auto begin() const noexcept { using std::end; return std::make_reverse_iterator(end(rng)); }
auto end() const noexcept { using std::begin; return std::make_reverse_iterator(begin(rng)); }
};
int main()
{
std::vector<int> my_stack;
my_stack.push_back(1);
my_stack.push_back(2);
my_stack.puhs_back(3);
// prints 3,2,1
for (auto const& elem : Reverse(my_stack)) {
std::cout << elem << ',';
}
}
Run Code Online (Sandbox Code Playgroud)
但是,执行嵌套应用程序Reverse不会产生原始迭代顺序 …
用g ++ 5.4,这个
struct B {
void f() {}
};
struct D : public B {
void g() {}
};
template <class T>
void foo(void (T::*)(), void (T::*)())
{}
int main()
{
foo(&D::f, &D::g);
}
Run Code Online (Sandbox Code Playgroud)
由于"推断出参数'T'('B'和'D')的冲突类型而失败".为什么不将T推导为D,完全匹配?
template <typename T> struct A {
A(T);
A(const A&);
};
int main()
{
A x(42); // #1
A y = x; // #2
}
Run Code Online (Sandbox Code Playgroud)
据我了解,T#1将使用第一个ctor生成的隐式演绎指南推导出.然后x将使用该ctor初始化.
但是对于#2,T将使用复制演绎候选人推断(根据我的理解,这是演绎指南的特定情况)(然后y将使用第二个ctor初始化).
为什么不能T使用复制版本生成的(隐含)演绎指南来推导#2?
我想我只是不明白复制演绎候选人的一般目的.
c++ templates template-argument-deduction argument-deduction c++17
我希望能够使用新的模板参数推导的地方之一就是构建带有自定义比较器的std::set's/std::maps /任何其他容器 - 我的目标是创建一个单行语句,这将创建一个高效的用lambda比较器设置.自C++ 11以来我能做的是:
std::set<int, std::function<bool(int, int)>> s([](int a, int b) {return a > b;});
Run Code Online (Sandbox Code Playgroud)
但由于它使用std::function,它明显变慢.
另一种选择是:
auto mycomp = [](int a, int b) {return a > b; };
std::set<int, decltype(mycomp)> s(mycomp);
Run Code Online (Sandbox Code Playgroud)
它完成了工作,但1)它需要2行,并创建mycomp变量2)我需要mycomp显式传递的类型.
正如我在参考页面上看到的那样,没有一个标准容器有针对这种情况的扣除指南.不幸的是,我担心它甚至无法用当前的语言标准(C++ 17)完成,因为人们可以找到:
仅当不存在模板参数列表时,才会执行类模板参数推导.如果指定了模板参数列表,则不会进行演绎.
这背后的原因是什么?为什么他们不允许部分论证扣除?我想它有些问题我忽略了,但在我看来,它会有所帮助.
c++ templates template-argument-deduction argument-deduction c++17