gpt4 book ai didi

c++ - 我可以有一个 std::vector 的模板函数指针吗?

转载 作者:行者123 更新时间:2023-12-01 22:47:27 27 4
gpt4 key购买 nike

我有一个模板函数,我想在 std::vector 内部存储一个指针.

该函数如下所示:

template<typename T> void funcName(T& aT, std::vector<std::string>& fileName){...}

现在我想在 std::vector 中存储指向此类函数的多个指针.对于非模板函数,我会这样做:
typedef std::vector<std::string> string_vt;
typedef void func_t(T&, string_vt&);
typedef func_t* funcPointer;
typedef std::vector<funcPointer> funcPointer_vt;

但是模板函数的正确语法是什么?我该如何存储它们?

编辑:首先,感谢您的快速回复。这是我关于 Stack Overflow 的第一个问题,很抱歉没有提供足够的信息。

T 的集合是有限的,它可以是 ClassA 类型,也可以是 ClassB 类型。在这些函数模板中,我想使用一些硬编码数据对 T(即 ClassA 或 ClassB)进行更改。我有 8 个这样的函数,它们基本上启动了一个默认构造的 T,其中包含特定于该函数的数据。在我的程序中,我想启动 2*8 个默认构造的 T(8 个 ClassA 和 8 个 ClassB)。因此,我运行了一个 for 循环,一个接一个地调用函数,以使用函数的主体数据启动我的 T 对象。
for(int i = 0; i < initT.size(); ++i){
init_T[i]<T>(someT, fileName);
}

for 循环的迭代次数与 vector 内的函数指针一样多。在每次迭代时,该函数都会使用一些先前默认构造的 T 和一些其他参数来调用。最后的目标是拥有 8 个具有特定于功能的数据的初始 T。

编辑2:如果有帮助,这里有一些实际的源代码。在以下函数模板中,我想访问函数指针 vector 以调用相应的函数。
template<typename T_Relation, typename T_Relation_Vec, bool row>
void bulk_load(initRelation_vt& aInitFunctions, T_Relation_Vec& aRel_Vec, const bool aMeasure, const uint aRuns, const char* aPath)
{
for(size_t i = 0; i < aRuns; ++i)
{
MemoryManager::freeAll();
aRel_Vec.clear();
string_vt fileNames;
for(size_t j = 0; j < aInitFunctions.size(); ++j)
{
aRel_Vec.emplace_back(T_Relation());
aInitFunctions[j]<T_Relation>(aRel_Vec[j], fileNames);
BulkLoader bl(fileNames[j].c_str(), tuples, aRel_Vec[j], delimiter, seperator);
Measure lMeasure;
if(aMeasure)
{
lMeasure.start();
}
try
{
bl.bulk_load();
if(row)
{
BulkInsertSP bi;
bi.bulk_insert(bl, aRel_Vec[j]);
}
else
{
BulkInsertPAX bi;
bi.bulk_insert(bl, aRel_Vec[j]);
}
}
catch(std::exception& ex)
{
std::cerr << "ERROR: " << ex.what() << std::endl;
}
lMeasure.stop();
if(aMeasure)
{
std::ofstream file;
file.open (aPath, std::ios::out | std::ios::app);
//print_result(file, flag, lMeasure.mTotalTime());
file.close();
}
}
}
}

这一行是访问函数模板指针 vector 的地方。
aInitFunctions[j]<T_Relation>(aRel_Vec[j], fileNames);

最佳答案

模板是 static polymorphism 的高级技术.在像 C++ 这样的类型化语言中,如果没有静态多态性,您必须单独定义使用的每个实体并精确指示引用的每个实体。

C++ 中的静态多态机制允许自动指示函数或方法并将其推迟到通过 构建重载 .它允许您通过 一次定义多个共享某些特征的实体。模板并将特定特化的定义推迟到构建,从使用中推断出来。

(注意,在各种场景下,静态多态允许单独的代码,这样使用和定义的变化是独立的,这非常有用。)

这种机制的重要含义是模板的每个特化可能是不同的类型。目前尚不清楚,在我做出回应时,您是要在一种类型的容器中存储指向单一类型还是多种类型的特化的指针。可能性还取决于函数模板的参数和结果类型。

C++ 中的函数的类型是其参数类型列表及其返回类型的组合。换句话说,接受和返回相同类型的两个函数是相同的类型。如果您的函数模板既没有采用或返回模板参数类型(即 T )也没有模板化类型(例如 std::vector<T> ),则此函数模板的每个特化都将采用和返回相同的类型,因此将是相同的类型。

    template <typename T>
int func() { ... }

这个(可以说是无用的)函数模板不接受任何参数并返回 int , 随便 T用于专门化模板。因此,在参数定义为 int (*f)() 的任何地方都可以使用指向它的指针。 .在这种情况下,您可以将指针指向一个 vector 中的任何特化。
    typedef std::vector<std::string> string_vt;
typedef int func_t();
typedef func_t* funcPointer;
typedef std::vector<funcPointer> funcPointer_vt;

funcPointer x = &func<int>;
funcPointer y = &func<float>;

可以看出,函数模板的每个特化都是相同的类型,并且两个指针都放在同一个容器中。

下一种情况 - 如果函数头取决于模板参数怎么办?每个特化都会有不同的签名,即不同的函数类型。指向所有这些的指针将是不同的类型 - 所以甚至不可能 typedef这个指针一次。
    template <typename T>
void func(std::vector<T> param) { ... }

在这种情况下,函数模板特化是不同的类型,具体取决于 T用来专攻。
    typedef int func_t_int(std::vector<int>);
typedef func_t_int* funcPointerInt;
typedef std::vector<funcPointerInt> funcPointerInt_vt;

typedef float func_t_float(std::vector<float>);
typedef func_t_float* funcPointerFloat;
typedef std::vector<funcPointerFloat> funcPointerFloat_vt;

funcPointerInt x = &func<int>;

funcPointerFloat x = &func<float>;

特化有不同的类型,因为它们采用不同类型的 vector 。指针不适契约(Contract)一个容器。

在这一点上值得一提的是,在这种情况下,没有必要单独定义每个指针类型。它们可以是模板类型:
    template <typename T>
using funcPointer = void (*)(std::vector<T>);

现在允许 funcPointer<int>用作类型限定符,代替之前的 funcPointerInt .
    funcPointer<float> y = &func<float>;

在更复杂的情况下,可以创建一个模板,它的每个特化都是不同的类型,然后将使用具体 vector 的单个实例来存储指向模板的只有一个特化类型的函数的各种指针。虽然像示例中这样的简单模板只能为每种类型生成一个函数,但因为每个特化都会产生一种类型的函数和该类型的一个函数,但并非不可能设想一种情况,即获得指向函数的各种指针,都指向特化和通常的功能,也许来自各种来源。所以这项技术可能很有用。

但另一种情况是,尽管模板的每个特化都是不同类型的,但仍然需要在单个 std::vector 中存储指向各种特化的指针。 .在这种情况下 动态多态会有所帮助。要存储不同类型的值,fe。在一种类型的变量中指向不同类型函数的指针需要 继承 .可以在定义为父类(super class)的字段中存储任何子类。 备注 但是,这不太可能真正完成任何事情,也可能不是您真正想要的。

我现在看到了两种普遍的可能性。要么使用带有方法的类模板,该方法继承自非模板类。
    template <typename T>
class MyClass : BaseClass
{
public:
T operator()(const T& param, int value);
}

MyClass<int> a;
MyClass<float> b;
BaseClass* ptr = &a;
ptr = &b;

虽然这个类的每个特化可能是不同的类型,但它们都共享父类(super class) BaseClass ,所以是指向 BaseClass 的指针实际上可以指向它们中的任何一个,还有一个 std::vector<funcPointerBase>可以用来存储它们。通过重载 operator()我们创建了一个模仿函数的对象。这种类的有趣特性是它可以使用参数构造函数创建多个实例。如此有效的类模板产生多种类型的特化,反过来每个特化类都可以产生不同参数化的实例。
    template <typename T>
class MyClass : BaseClass
{
int functor_param;
public:
MyClass(int functor_param);
T operator()(const T& param, int value);
}

此版本允许创建以不同方式工作的实例:
    MyClass<int> a(1);
MyClass<int> b(2);
MyClass<float> c(4);
MyClass<int>* ptr = &a;
ptr = &b;
ptr = &c;

我不是仿函数方面的专家,只是想介绍一下总体思路。如果它看起来很有趣,我建议现在研究它。

但从技术上讲,我们不存储函数指针,只是普通的对象指针。好吧,如前所述,我们需要继承来使用一种类型的变量来存储各种类型的值。因此,如果我们不使用继承来将过程函数交换为动态多态的东西,我们必须对指针做同样的事情。
    template <typename T>
T func(std::pair < T, char>) {}

template <typename T>
using funcPointer = T(*)(std::pair<T, char>);

template <typename T>
class MyPointer : BasePointer
{
funcPointer<T> ptr;

public:
MyPointer(funcPointer<T> ptr);
T()(std::pair <T, char>) operator*(std::pair <T, char> pair)
{
*ptr(pair);
}
};

这再次允许创建单个 std::vector<BasePointer>存储所有可能的伪函数指针。

现在是非常重要的一点。在这两种情况下,您将如何调用它们?因为在这两种情况下它们都存储在一个 std::vector<> 中。 ,它们被视为基本类型。特定的函数调用需要特定类型的参数并返回特定类型。如果所有子类都可以以相同的方式执行任何操作,则可以通过在基类中定义这样的方法来公开它(在使用仿函数或指针的任何一种情况下……或?),但特定的专用函数调用不是那种的东西。经过所有这些努力,您最终想要执行的每个函数调用都将是不同的类型,需要不同类型的参数和/或返回不同类型的值。因此,它们永远不可能在通常情况下都适契约(Contract)一个地方,而不是模板化代码,执行中的相同环境。如果他们这样做了,那么首先就不需要动态多态来解决这个问题。

可以做的一件事 - 非常不鼓励并且可能破坏动态多态性的目的 - 是在运行时检测子类类型并相应地进行。研究一下,如果你确信你有一个很好的例子来使用它。最有可能的是,这可能是一个很大的反模式。

但从技术上讲,您可能想做的任何事情都以某种方式成为可能。

关于c++ - 我可以有一个 std::vector 的模板函数指针吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41749792/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com