C++17 标准(最终草案)的[temp.arg.explicit]/3说明了使用明确指定的模板参数列表来推导函数模板参数:
在推导完成但失败或 [...] 的上下文中,如果指定了模板参数列表,并且它与任何默认模板参数一起标识单个函数模板特化,则模板 ID 是函数模板特化。
这如何应用于参数包?
考虑
template<typename...>
struct S {
S(int) {}
};
template<typename... A>
void f(S<A...>) {}
int main() {
f<int>(0);
}
Run Code Online (Sandbox Code Playgroud)
这在 MSVC 上编译,但不在 GCC 和 Clang 上编译,请参阅Godbolt。这也是我的直觉,它应该失败,因为演绎会失败,但上面的引用似乎暗示即使演绎失败,因为f<int>(在我的理解中)唯一标识了一个模板专业化,f<int>应该被认为是指那个专业化和然后调用它,没有重载决议,这将起作用,隐式转换0为S<int>.
我对引用的理解有什么问题,还是 MSVC 确实正确?
请注意,如果我们尝试调用f<>(0);(我猜应该通过上述考虑可以工作)所有三个编译器都拒绝编译。
我有一个包含两个文件的小项目:
主程序
#include <string>
template<int I>
int getint(int i)
{
extern std::string var;
return var.size() * i;
}
int main()
{
return getint<2>(2);
}
Run Code Online (Sandbox Code Playgroud)
和子.cpp
#include <string>
extern std::string var;
std::string var = "Hello";
Run Code Online (Sandbox Code Playgroud)
但是当我编译项目时,链接器给出了错误:
-------------- Clean: Debug in test (compiler: GNU GCC Compiler)---------------
Cleaned "test - Debug"
-------------- Build: Debug in test (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -Wall -fexceptions -g -c C:\Users\Fan\Downloads\test\test\main.cpp -o obj\Debug\main.o
mingw32-g++.exe -Wall -fexceptions -g -c C:\Users\Fan\Downloads\test\test\sub.cpp -o obj\Debug\sub.o
mingw32-g++.exe -o bin\Debug\test.exe obj\Debug\main.o obj\Debug\sub.o
obj\Debug\main.o: In …Run Code Online (Sandbox Code Playgroud) 在我的代码中,我有一个名为的接口AbstactDataModel,用作所有数据模型类的起点。实现这一点是为了让我知道无论xyzModel我需要什么类,它都会有一个fromJson(Map<String, dynamic> json)函数,该函数将返回使用给定的 json 和type.
// In abstract_model.dart
abstract class AbstractDataModel {
///
/// returns a String containing the class name
/// For example, the class ColumnModel will return 'column'
///
String get type;
///
/// Will call the [.fromJson] constructor and return a new instance of the
/// object
///
dynamic fromJson(Map<String, dynamic> json);
}
Run Code Online (Sandbox Code Playgroud)
下面是一个扩展了 DataModel 类的示例AbstractDataModel:
// in group_model.dart
class GroupModel extends AbstractDataModel {
int _id; …Run Code Online (Sandbox Code Playgroud) 我确实希望能够在不声明 lambda 的情况下使用 extFunction or std::maxorstd::min作为 square 方法的参数:
template<typename T>
T extFunction(T a, T b)
{
return a;
}
class Stuff
{
public:
template <typename F>
int square(int num, int num2, F&& func)
{
return func(num, num2);
}
};
int main()
{
Stuff s;
std::cout << s.square(1, 2, std::max<int>) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是编译器(gcc 11.1)告诉我:
函数不明确:“无法推导出模板参数‘
F’”
没有 lambdas 有没有一种简单的方法可以做到这一点?
编辑:
也许展示如何使用 lambdas 做到这一点会很有趣:
std::cout << s.square(1,2,[](auto&& a, auto&& b){return std::max(a,b);}) << std::endl; …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)将调用第二版模板,因为没有办法将指针转换为对数组的引用。将 …
我尝试在GNU的链接器包装选项的帮助下包装模板函数.代码如下所示:
// f.h
template<typename T>
void f(T t) {
}
// bar.h
void bar();
// bar.cpp
#include "bar.h"
#include "f.h"
void bar() {
f(42);
}
// test.cpp
extern "C" {
extern void __real__Z1fIiEvT_(int i);
void __wrap__Z1fIiEvT_(int i) {
__real__Z1fIiEvT_(i);
}
}
int main() {
bar();
}
Run Code Online (Sandbox Code Playgroud)
上面显示的代码与以下命令链接:
g++ -Xlinker -wrap=_Z1fIiEvT_ -o test test.o bar.o
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不起作用,并且始终调用原始函数f而不是我的包装版本__wrap__Z1fIiEvT_.你看到我犯过什么错误吗?
编辑:建议,我在这里附加nm的输出,以确保我没有使用模板函数的错位名称做任何错误:
$ g++ -c bar.cpp -o bar.o
$ nm bar.o
0000000000000000 W _Z1fIiEvT_
Run Code Online (Sandbox Code Playgroud) 这是一个例子:
#include <string>
#include <algorithm>
#include <memory>
using std::string;
int main()
{
string str = "This is a string";
// ok: needn't using declaration, ADL works
auto it = find(str.begin(), str.end(), 'i');
// error: why ADL doesn't work?
std::shared_ptr<string> sp = make_shared<string>(str);
}
Run Code Online (Sandbox Code Playgroud)
当我试图编译这个程序时,编译器抱怨:
error: no template named 'make_shared'; did you mean 'std::make_shared'?
std::shared_ptr<string> sp = make_shared<string>(str); // error...
^~~~~~~~~~~
std::make_shared
Run Code Online (Sandbox Code Playgroud)
我猜第一个函数find不需要using声明,因为依赖于参数的lookup(ADL):编译器会搜索名称空间string(即std)的定义find.但对于第二个函数make_shared,它似乎ADL不起作用:我必须使用std::make_shared或 …
给定一个非可变函数模板:
template<class T>
void f(void(t)(T));
Run Code Online (Sandbox Code Playgroud)
还有一些简单的功能:
void f1(int);
void f2(char);
Run Code Online (Sandbox Code Playgroud)
这有效:
f(f1);
Run Code Online (Sandbox Code Playgroud)
类型t变成了void (*)(int).
但是,可变对应物:
template<class... T>
void f(void(...t)(T));
// call
f(f1, f2);
Run Code Online (Sandbox Code Playgroud)
不起作用.编译器(gcc&clang)抱怨不匹配的类型void(T)和void (*)(int).见DEMO.
请注意,如果*明确添加,它可以正常工作:
template<class... T>
void f(void(*...t)(T));
Run Code Online (Sandbox Code Playgroud)
那么,为什么非可变参数可以衰减函数类型而可变参数不能?
c++ language-lawyer function-templates variadic-templates c++11
前几天,我偶然发现了这个问题,无法弄清楚哪个答案是正确的,或者都不能接受。
具体来说,我指的是对OtherFunction中的bar(T {})的调用。从我已经能够在编译器资源管理器上进行测试的角度来看,这个决定似乎有些分歧。当gcc和clang编译代码没有问题时,msvc和icc同意它是模棱两可的。
通过与参数相关的查找,隐藏的命名空间中的功能栏变得可见。此外,msvc / icc将全局命名空间中的bar声明视为候选,而gcc / clang则不这样做。似乎不应该考虑全局命名空间中的声明,因为它是在调用bar(T {})之后声明的,但是我不确定我是在正确读取不合格名称查找的规则还是标准是在这方面模棱两可。
编辑:只要使用/ permissive-选项,看起来msvc已修复此问题(https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/)
template <typename T>
inline void OtherFunction () {
bar(T{});
}
namespace hidden {
struct Foo {};
inline void bar (Foo foo) {}
}
inline void bar (hidden::Foo foo) {}
void Function () {
OtherFunction<hidden::Foo>();
}
Run Code Online (Sandbox Code Playgroud) c++ function-templates name-lookup argument-dependent-lookup
假设我有一些模板函数,它返回传递给它的一些可迭代对象的中值。
就像是:
template<typename T>
decltype(auto) find_median_sorted(T begin)
{
// some code here
}
Run Code Online (Sandbox Code Playgroud)
现在我想确保我T始终是可迭代的。我正在尝试学习如何concepts在 C++ 中使用,那么我可以concept在这里使用某种方法来确保T它是可迭代的吗?
我确信还有其他方法来检查它是否可迭代,但这是否是一个错误的用例concepts?我还在这里发现了这篇与可迭代元素相关的文章,但我不确定这如何适用于我的情况。
c++ ×9
templates ×3
c++-concepts ×1
c++11 ×1
c++20 ×1
compiler-bug ×1
dart ×1
flutter ×1
gnu ×1
lambda ×1
linker ×1
name-lookup ×1