英文:
Calling nested static members in c++
问题
template<typename TH, typename ... TGs>
static void static_recursive(TGs &... gs) {
MyStruct::st_printno<TH>();
}
英文:
I am creating a program that calls a nested template function. It works fine if the nested template function is a class member (i.e. by adding this->template). But how to make it work in the static case (i.e. the ???)
The code example is a bit complex, but the most important lines are the difference between the this->template test_recursive_sub<TH>(gs...);
and the static version ??? test_recursive_sub<TH>(gs...);
in calling a nested template function in the same class. What has to replace the ???
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
struct TestObject1 {
using Type = int;
};
struct TestObject2 {
using Type = int;
};
struct TestObject3 {
using Type = int;
};
struct MyStruct {
template<typename TH>
void printno() {
typename TH::Type num = 100;
std::cout << num << std::endl;
}
template<typename TH>
void static st_printno() {
typename TH::Type num = 100;
std::cout << num << std::endl;
}
template<typename TH, typename ... TG>
void test_recursive_sub(TG &... gs) {
printno<TH>();
}
template<typename TH, typename ... TG>
void test_recursive(TG &... gs) {
this->template test_recursive_sub<TH>(gs...);
}
template<typename TH, typename ... TGs>
static void recursive_sub(TGs &... gs) {
MyStruct::st_printno<TH>();
}
template<typename TH, typename ... TGs>
static void static_recursive(TGs &... gs) {
??? test_recursive_sub<TH>(gs...);
}
};
int static_template_nesting() {
TestObject1 to1;
TestObject2 to2;
MyStruct ro1;
ro1.test_recursive<TestObject2>(to1, to1, to2);
ro1.test_recursive<TestObject3>(to2);
MyStruct::static_recursive<TestObject2>(to1, to1, to2);
MyStruct::static_recursive<TestObject3>(to2);
return 0;
}
答案1
得分: 2
你对它的写法,没有递归(没有函数调用自身)。
此外,静态函数只能调用静态函数(非静态应该由对象调用)。
模板参数没有正确声明或使用。
首先声明一个函数的通用版本,该版本将接受第一个参数(head
)和其他参数(tails
)。你似乎已经在这条路上了。
如果tails
中的参数数量非零,那么你可以递归:处理head
,然后将tails
转发到相同的函数,而无需指定模板参数:函数将自行推断它们。
如果tails
中的参数数量为零,则调用特定的实现。
在C++17之前,你将为每种情况编写一个函数,并使用SFINAE保留一个合法的重载。你可以通过在模板参数中添加std::enable_if_t
,来完成这个操作,对于单参数情况,它将无效。
自C++17以来,情况变得更简单了,只需编写一个带有if constexpr
的单一函数,就像编写传统递归一样。
这里是修复:
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
// 在C++14之前将使用std::enable_if
#include <type_traits>
struct TestObject1 {
using Type = int;
};
struct TestObject2 {
using Type = int;
};
struct TestObject3 {
using Type = int;
};
struct MyStruct {
template <typename TH>
void printno() {
typename TH::Type num = 100;
std::cout << num << std::endl;
}
template <typename TH>
void static st_printno() {
typename TH::Type num = 100;
std::cout << num << std::endl;
}
template <typename TH, typename... TG>
void test_recursive_sub(TG &...gs) {
printno<TH>();
}
template <typename TH, typename... TG>
void test_recursive(TG &...gs) {
this->template test_recursive_sub<TH>(gs...);
}
template <typename TH, typename... TGs>
static void recursive_sub(TGs &...gs) {
MyStruct::st_printno<TH>();
}
// C++14版本
// 仅对多参数重载
// 如果只有一个参数,SFINAE将消除它
template <typename TH, typename... TGs,
std::enable_if_t<(sizeof...(TGs) > 0), bool> = true>
static void static_recursive(TH &head, TGs &...tail) {
std::cout << "处理一个参数,然后 " << sizeof...(TGs) << " 个参数"
<< std::endl;
static_recursive(tail...);
}
template <typename TH>
// 仅对单参数重载
static void static_recursive(TH &head) {
std::cout << "处理单个元素" << std::endl;
}
// C++17版本
// template <typename TH, typename... TGs>
// static void static_recursive(TH &head, TGs &...tail) {
// if constexpr (sizeof...(TGs) > 0) {
// std::cout << "处理一个参数,然后 " << sizeof...(TGs) << " 个参数"
// << std::endl;
// static_recursive(tail...);
// } else {
// std::cout << "处理单个元素" << std::endl;
// }
// }
};
int main() {
TestObject1 to1;
TestObject2 to2;
MyStruct ro1;
ro1.test_recursive<TestObject2>(to1, to1, to2);
ro1.test_recursive<TestObject3>(to2);
// 无需提供模板参数,它们会被推断
MyStruct::static_recursive(to1, to1, to2);
MyStruct::static_recursive(to2);
return 0;
}
英文:
The way you right it, there is no recursion (no function calling itself).
Besides, a static function can only call a static function (non static should be called by an object).
The template arguments were not declared neither used properly.
First declare a generic version of the function that will take a first argument (head
) and the other ones (tails
). You seemed to be on this track already.
If the number of arguments in tails
is non zero then you can recurse: process head
then forward tails
to the same function without specifying template arguments: the function will deduce them by itself.
If the number of arguments in tails
is zero, you call a special implementation.
Before C++17, you will write a function for each case and use SFINAE to leave only one overload well-formed. You can do that by adding an std::enable_if_t
, in the template parameters, that will be invalid for the single argument case.
Since C++17 it's easier, simply write a single function with an if constexpr
, as you would write a classical recursion.
Here is the fix:
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
// will use std::enable_if until C++14
#include <type_traits>
struct TestObject1 {
using Type = int;
};
struct TestObject2 {
using Type = int;
};
struct TestObject3 {
using Type = int;
};
struct MyStruct {
template <typename TH>
void printno() {
typename TH::Type num = 100;
std::cout << num << std::endl;
}
template <typename TH>
void static st_printno() {
typename TH::Type num = 100;
std::cout << num << std::endl;
}
template <typename TH, typename... TG>
void test_recursive_sub(TG &...gs) {
printno<TH>();
}
template <typename TH, typename... TG>
void test_recursive(TG &...gs) {
this->template test_recursive_sub<TH>(gs...);
}
template <typename TH, typename... TGs>
static void recursive_sub(TGs &...gs) {
MyStruct::st_printno<TH>();
}
// C++14 version
// overload for multiple argument only
// SFINAE will eliminate it if there is only one argument
template <typename TH, typename... TGs,
std::enable_if_t<(sizeof...(TGs) > 0), bool> = true>
static void static_recursive(TH &head, TGs &...tail) {
std::cout << "process an arg then " << sizeof...(TGs) << " args"
<< std::endl;
static_recursive(tail...);
}
template <typename TH>
// overload for single argument only
static void static_recursive(TH &head) {
std::cout << "process single element" << std::endl;
}
// C++17 version
// template <typename TH, typename... TGs>
// static void static_recursive(TH &head, TGs &...tail) {
// if constexpr (sizeof...(TGs) > 0) {
// std::cout << "process an arg then " << sizeof...(TGs) << " args"
// << std::endl;
// static_recursive(tail...);
// } else {
// std::cout << "process single element" << std::endl;
// }
// }
};
int main() {
TestObject1 to1;
TestObject2 to2;
MyStruct ro1;
ro1.test_recursive<TestObject2>(to1, to1, to2);
ro1.test_recursive<TestObject3>(to2);
// no need to give template arguments, they are deduced
MyStruct::static_recursive(to1, to1, to2);
MyStruct::static_recursive(to2);
return 0;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论