我有一个模板函数,我想在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循环具有与向量内部的函数指针一样多的迭代。在每次迭代时,使用一些先前默认构造的T和一些其他参数调用该函数。最后,目标是让8个启动的T具有特定于该功能的数据。
EDIT2:如果有帮助,这里有一些实际的源代码。在以下函数模板中,我想访问我的函数指针向量,以便调用相应的函数。
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();
}
}
}
}
这一行是访问函数模板指针向量的地方。
aInitFunctions[j]<T_Relation>(aRel_Vec[j], fileNames);
答案 0 :(得分:10)
模板是static polymorphism的高级技术。在类似C ++的类型语言中,如果没有静态多态,则必须单独定义所使用的每个实体并精确指示所引用的每个实体。
C ++中静态多态的机制允许自动指示函数或方法,并将其推迟到通过重载构建。它允许您通过模板一次定义多个共享某些特征的实体,并将特定特化的定义推迟到构建,从使用中推断出来。
(请注意,在各种情况下,静态多态允许单独的代码,因此使用和定义的更改是独立的,这非常有用。)
这种机制的重要含义是模板的每个特化都可能是不同类型的。目前还不清楚,当我回复时,您是否想要在一种类型的容器中存储指向单个或多个类型的特化的指针。可能性还取决于函数模板的参数和结果类型。
C ++中的函数的类型是其参数类型列表及其返回类型的组合。换句话说,获取和返回相同类型的两个函数具有相同的类型。如果你的函数模板既没有采用或返回模板参数类型(即。T
)也没有模板化类型(例如std::vector<T>
),那么这个函数模板的每个特化都将采用并返回相同的类型,因此是一个相同类型的函数。
template <typename T>
int func() { ... }
这个(可以说是无用的)函数模板不带参数并返回int
,无论T
用于专门化模板。因此,只要参数定义为int (*f)()
,就可以使用指向它的指针。在这种情况下,您可以在一个向量中保留指向任何特化的指针。
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>;
专业化有不同的类型,因为它们采用不同类型的向量。指针不适合放在同一个容器中。
此时值得一提的是,在这种情况下,没有必要单独定义每个指针类型。它们可以是模板类型:
template <typename T>
using funcPointer = void (*)(std::vector<T>);
现在允许将funcPointer<int>
用作类型限定符,而不是之前的funcPointerInt
。
funcPointer<float> y = &func<float>;
在更复杂的情况下,可以创建一个模板,其每个特化都是不同的类型,然后使用单个具体向量实例来存储指向模板中一个特化类型的函数的各种指针。虽然示例中的简单模板只能为每个类型生成一个函数,但由于每个特化都会产生一种类型的函数和一种类型的函数,因此不可能设想获得各种函数指针的场景。 ,无论是专业化还是常规功能,也许来自各种来源。所以这项技术可能很有用。
但另一种情况是,尽管模板的每个特化都是不同类型的,但仍需要在单std::vector
中存储指向各种特化的指针。在这种情况下,动态多态将会有所帮助。为了存储不同类型的值,fe。在一种变量中,指向不同类型函数的指针需要继承。可以将任何子类存储在定义为超类的字段中。 注意然而,这不可能真正完成任何事情,也可能不是你真正想要的。
我现在看到两种普遍的可能性。使用带有方法的类模板,该方法继承自非模板类。
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;
虽然这个类的每个特化都可以是不同的类型,但它们都共享超类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<>
中,因此它们被视为基类型。特定函数调用需要特定类型的参数并返回特定类型。如果所有子类都可以以相同的方式执行任何操作,则可以通过在基类中定义这样的方法(在任一场景中使用仿函数或指针......)来公开它,但是特定的专用函数调用不是那种事情在所有这些困难之后,您最终想要执行的每个函数调用都是不同的类型,需要不同类型的参数和/或返回不同类型的值。因此,他们可能永远不会在通常的情况下适合相同的位置,而不是模板化的代码,执行中的相同情况。如果他们这样做了,那么首先就不需要动态多态来解决这个问题。
可以做的一件事 - 非常不鼓励并且可能违背动态多态的目的 - 是在运行时检测子类类型并相应地继续。研究一下,如果你确信你有一个很好的案例来使用它。但最有可能的是,这可能是一个很大的反模式。
但从技术上讲,你可能想做的任何事情都有可能。
答案 1 :(得分:1)
如果我正确地理解了你,我可能会有一个非常简单有效的解决方案:
JSONObject json = new JSONObject(stringreadfromsqlite);
ArrayList<Publication> items = json.optJSONArray("uniqueArrays");
瞧!!
直到c ++ 17, template<class...Ts>
struct functor{
//something like a dynamic vtable
std::tuple<void(*)(Ts&,std::vector<std::string>&)...> instantiated_func_ptr;
template<class T>
void operator ()(T& aT,std::vector<std::string>& fileName){
get<void(*)(T&,std::vector<std::string>&)>(instantiated_func_ptr)
(aT,fileName);
}
};
未定义,因此我们必须定义它(在上面模板仿函数的定义之前):
get<typename>
以及展示如何使用它的示例:
template<class T,class...Ts>
struct find_type{
//always fail if instantiated
static_assert(sizeof...(Ts)==0,"type not found");
};
template<class T,class U,class...Ts>
struct find_type<T,U,Ts...>:std::integral_constant<size_t,
find_type<T,Ts...>::value+1>{};
template<class T,class...Ts>
struct find_type<T,T,Ts...>:std::integral_constant<size_t,0>{};
template<class T,class...Ts>
constexpr decltype(auto) get(const std::tuple<Ts...>& t){
return get<find_type<T,Ts...>::value>(t);
}
在实践中,它只是虚拟呼叫机制的再现,
struct A{
void show() const{
std::cout << "A" << "\n";
}
};
struct B{
void show() const{
std::cout << "B" << "\n";
}
};
template<class T>
void func1(T& aT,std::vector<std::string>& fileName){
std::cout << "func1: ";
aT.show();
}
template<class T>
void func2(T& aT,std::vector<std::string>& fileName){
std::cout << "func2: ";
aT.show();
}
template<class T>
void func3(T& aT,std::vector<std::string>& fileName){
std::cout << "func3: ";
aT.show();
}
using functorAB = functor<A,B>;
int main(){
auto functor1=functorAB{{func1,func1}};//equivalent to functorAB{{func1<A>,func1<B>}}
auto functor2=functorAB{{func2,func2}};
auto functor3=functorAB{{func3,func3}};
auto v=std::vector<functorAB>{functor1,functor2,functor3};
auto a=A{};
auto b=B{};
auto fileNames = std::vector<std::string>{"file1","file2"};
for(auto& tf:v)
tf(a,fileNames);
for(auto& tf:v)
tf(b,fileNames);
}
中的tuple
是一种虚拟表。这段代码不是
比使用虚拟编写抽象functor
更有效
每个A类和B类的operator()然后为每个类实现它
你的函数......但它更简洁,更易于维护,并且可能产生更少的二进制代码。