标签: function-templates

带有显式模板参数列表和 [temp.arg.explicit]/3 的函数调用的推导失败

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>应该被认为是指那个专业化和然后调用它,没有重载决议,这将起作用,隐式转换0S<int>.

我对引用的理解有什么问题,还是 MSVC 确实正确?


请注意,如果我们尝试调用f<>(0);(我猜应该通过上述考虑可以工作)所有三个编译器都拒绝编译。

c++ function-templates template-argument-deduction

7
推荐指数
1
解决办法
103
查看次数

链接器错误:使用外部变量的函数模板中的未定义引用

我有一个包含两个文件的小项目:

主程序

#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)

c++ linker-errors unresolved-external function-templates

7
推荐指数
0
解决办法
185
查看次数

Flutter 使用 T 扩展接口创建通用函数

语境

在我的代码中,我有一个名为的接口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)

generic-programming function-templates dart flutter

7
推荐指数
1
解决办法
4012
查看次数

在没有 lambda 的情况下将模板化函数作为方法参数传递?

我确实希望能够在不声明 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)

c++ lambda templates function-pointers function-templates

7
推荐指数
1
解决办法
268
查看次数

接受 const char(&amp;)[N] 的函数模板是否比接受 const T&amp; 的函数模板更专业?

我定义了两个版本的函数模板,名为compare

\n
#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}\n
Run Code Online (Sandbox Code Playgroud)\n

在使用c++11std的CPP Primer(第5版)一书中,作者说compare(p1, p2)将调用第二版模板,因为没有办法将指针转换为对数组的引用。将 …

c++ function-templates overload-resolution compiler-bug

7
推荐指数
1
解决办法
176
查看次数

包装C++模板函数

我尝试在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)

c++ linker gnu function-templates

6
推荐指数
1
解决办法
965
查看次数

依赖于参数的查找和函数模板

这是一个例子:

#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或 …

c++ templates function-templates argument-dependent-lookup

6
推荐指数
1
解决办法
331
查看次数

可变函数/非可变模板之间函数类型衰减的不一致性?

给定一个非可变函数模板:

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

6
推荐指数
1
解决办法
216
查看次数

该函数调用是否应该模棱两可?

前几天,我偶然发现了这个问题,无法弄清楚哪个答案是正确的,或者都不能接受。

具体来说,我指的是对OtherFunction中的bar(T {})的调用。从我已经能够在编译器资源管理器上进行测试的角度来看,这个决定似乎有些分歧。当gcc和clang编译代码没有问题时,msvc和icc同意它是模棱两可的。

通过与参数相关的查找,隐藏的命名空间中的功能栏变得可见。此外,msvc / icc将全局命名空间中的bar声明视为候选,而gcc / clang则不这样做。似乎不应该考虑全局命名空间中的声明,因为它是在调用bar(T {})之后声明的,但是我不确定我是在正确读取不合格名称查找的规则还是标准是在这方面模棱两可。

https://godbolt.org/z/HAS-Cv

编辑:只要使用/ 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

6
推荐指数
1
解决办法
116
查看次数

如何使用概念将模板限制为可迭代范围?

假设我有一些模板函数,它返回传递给它的一些可迭代对象的中值。

就像是:

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++ templates function-templates c++-concepts c++20

6
推荐指数
1
解决办法
945
查看次数