自动生成函数 header,可变参数模板
Autogenerate function header, variadic template
我有一个问题,我定义了一个模板class来应对不同维度的系统如下:
template <std::size_t N>
class system {
std::array<cv::Mat, N> matrices;
...
};
然后我需要定义不同的函数,根据系统的大小采用不同的参数。类似的东西:
template <>
template<typename T>
void system<1>::fun(T & a){ }
template <>
template<typename T>
void system<2>::fun(T & a, T & b){ }
template <>
template<typename T>
void system<3>::fun(T & a, T & b, T & c){ }
然而,尝试使用此策略时,编译器会出现以下错误:
Out-of-line definition of 'fun' does not match any declaration in 'system<3>'
此外,我希望 headers 函数能够根据模板参数 N
自动生成。我尝试使用可变参数模板但没有运气。
一个可能的解决方案是在class的函数体内定义函数(顺带一提:避免名称system()
:会与标准函数冲突),使用SFINAE,如下
template <std::size_t N>
class systemClass
{
private:
std::array<FooType, N> matrices;
public:
template<typename T, std::size_t M = N>
typename std::enable_if<M == 1U>::type fun(T & a) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 2U>::type fun(T & a, T & b) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 3U>::type fun(T & a, T & b, T & c) { }
};
Moreover I would like that the headers functions will be autogenerate based on the template parameter N. I tried to use variadic template but without fortune.
我同意 UnholySheep:我不清楚你到底想要什么,但我怀疑解决方案可能是一个 shell 脚本来生成代码。
如果您可以基于 N 自动生成,我想您可以编写代码来完成您通常需要的操作(您尝试使用可变参数的评论强化了这一点)。
不幸的是,您的函数也在 T
上进行了模板化,这一事实使事情变得比我想要的要复杂一些。有比我给出的更简单的解决方案,但我看到的唯一解决方案要求您显式指定类型,或者将检查推迟到运行时,这可以在编译时完成。就目前而言,我能看到做你想做的唯一方法是使用可变参数模板。这得到了你想要的大部分内容:
template <std::size_t N>
class System {
template <class ... Ts>
void fun(Ts& ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
}
};
我使用 static asserted 而不是 enable if,以使事情更简单(而且它不太可能产生影响,除非您计划有另一个名为 fun
的成员函数...不要不要那样做)。现在,此函数将只接受使用 N 个参数调用,但它将允许所有类型发生变化。您希望它们都相同。所以我们需要一点TMP。
template <class ... Ts>
struct all_same{};
template <class T>
struct all_same<T> : std::true_type {
using same_type = T;
};
template <class T, class ... Ts>
struct all_same<T, T, Ts...> : all_same<T, Ts...> {};
template <class T1, class T2, class ... Ts>
struct all_same<T1, T2, Ts...> : std::false_type {};
一些经典的递归 TMP 可以让我们得到我们想要的。两者都是 true 和 false 指示包中的所有类型是否相同,如果它们相同,我们可以访问通用类型。一旦我们有了一个通用类型,并验证了大小,我们就可以使用 pack 来初始化一个数组并对其进行循环,这样我们就不必在我们的函数中继续进行烦人的可变参数样式编程:
template <std::size_t N>
struct System {
template <class ... Ts>
void fun(Ts&... ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
using same = all_same<Ts...>;
static_assert(same::value, "All types must be the same!");
std::array<std::reference_wrapper<typename same::same_type>, N> x{ts...};
for (auto& e : x) { std::cerr << e << std::endl; }
}
};
修改此解决方案以满足您的确切需求将需要一些 C++ 专业知识,而且您还需要注意我们的某些棘手情况,例如当您同时传递字符串文字和 std::string
s 或您习惯于隐式转换的其他类型时,它将失败。不过,希望这能帮助你前进。现场示例:http://coliru.stacked-crooked.com/a/08ac23da33deb8ef.
我相信您还可以使用 integer_sequence
和别名模板使 foo
更通用。 (integer_sequence
是 c++14,但也存在 c++11 实现):
#include <utility>
#include <array>
template <class T, std::size_t>
using typer = T;
template <std::size_t N, class = std::make_index_sequence<N>>
struct S;
template <std::size_t N, std::size_t... Is>
struct S<N, std::index_sequence<Is...>>{
std::array<int, N> matrices;
template <class T>
void foo(typer<const T&, Is>... args) {
int dummy[] = { ((matrices[Is] = args), void(), 0)... };
static_cast<void>(dummy);
}
};
int main() {
S<3> s;
s.foo(1, 2, 3);
}
您可以使您的函数可变,但只接受正确数量的参数。它看起来像这样:
template <std::size_t N>
struct system {
template<typename... Ts>
auto fun(Ts&&... ts) -> std::enable_if_t<(N == sizeof...(Ts))> {
// function content
}
private:
std::array<cv::Mat, N> matrices;
};
如果参数数量等于N
.
,enable if 将只允许函数存在
我有一个问题,我定义了一个模板class来应对不同维度的系统如下:
template <std::size_t N>
class system {
std::array<cv::Mat, N> matrices;
...
};
然后我需要定义不同的函数,根据系统的大小采用不同的参数。类似的东西:
template <>
template<typename T>
void system<1>::fun(T & a){ }
template <>
template<typename T>
void system<2>::fun(T & a, T & b){ }
template <>
template<typename T>
void system<3>::fun(T & a, T & b, T & c){ }
然而,尝试使用此策略时,编译器会出现以下错误:
Out-of-line definition of 'fun' does not match any declaration in 'system<3>'
此外,我希望 headers 函数能够根据模板参数 N
自动生成。我尝试使用可变参数模板但没有运气。
一个可能的解决方案是在class的函数体内定义函数(顺带一提:避免名称system()
:会与标准函数冲突),使用SFINAE,如下
template <std::size_t N>
class systemClass
{
private:
std::array<FooType, N> matrices;
public:
template<typename T, std::size_t M = N>
typename std::enable_if<M == 1U>::type fun(T & a) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 2U>::type fun(T & a, T & b) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 3U>::type fun(T & a, T & b, T & c) { }
};
Moreover I would like that the headers functions will be autogenerate based on the template parameter N. I tried to use variadic template but without fortune.
我同意 UnholySheep:我不清楚你到底想要什么,但我怀疑解决方案可能是一个 shell 脚本来生成代码。
如果您可以基于 N 自动生成,我想您可以编写代码来完成您通常需要的操作(您尝试使用可变参数的评论强化了这一点)。
不幸的是,您的函数也在 T
上进行了模板化,这一事实使事情变得比我想要的要复杂一些。有比我给出的更简单的解决方案,但我看到的唯一解决方案要求您显式指定类型,或者将检查推迟到运行时,这可以在编译时完成。就目前而言,我能看到做你想做的唯一方法是使用可变参数模板。这得到了你想要的大部分内容:
template <std::size_t N>
class System {
template <class ... Ts>
void fun(Ts& ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
}
};
我使用 static asserted 而不是 enable if,以使事情更简单(而且它不太可能产生影响,除非您计划有另一个名为 fun
的成员函数...不要不要那样做)。现在,此函数将只接受使用 N 个参数调用,但它将允许所有类型发生变化。您希望它们都相同。所以我们需要一点TMP。
template <class ... Ts>
struct all_same{};
template <class T>
struct all_same<T> : std::true_type {
using same_type = T;
};
template <class T, class ... Ts>
struct all_same<T, T, Ts...> : all_same<T, Ts...> {};
template <class T1, class T2, class ... Ts>
struct all_same<T1, T2, Ts...> : std::false_type {};
一些经典的递归 TMP 可以让我们得到我们想要的。两者都是 true 和 false 指示包中的所有类型是否相同,如果它们相同,我们可以访问通用类型。一旦我们有了一个通用类型,并验证了大小,我们就可以使用 pack 来初始化一个数组并对其进行循环,这样我们就不必在我们的函数中继续进行烦人的可变参数样式编程:
template <std::size_t N>
struct System {
template <class ... Ts>
void fun(Ts&... ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
using same = all_same<Ts...>;
static_assert(same::value, "All types must be the same!");
std::array<std::reference_wrapper<typename same::same_type>, N> x{ts...};
for (auto& e : x) { std::cerr << e << std::endl; }
}
};
修改此解决方案以满足您的确切需求将需要一些 C++ 专业知识,而且您还需要注意我们的某些棘手情况,例如当您同时传递字符串文字和 std::string
s 或您习惯于隐式转换的其他类型时,它将失败。不过,希望这能帮助你前进。现场示例:http://coliru.stacked-crooked.com/a/08ac23da33deb8ef.
我相信您还可以使用 integer_sequence
和别名模板使 foo
更通用。 (integer_sequence
是 c++14,但也存在 c++11 实现):
#include <utility>
#include <array>
template <class T, std::size_t>
using typer = T;
template <std::size_t N, class = std::make_index_sequence<N>>
struct S;
template <std::size_t N, std::size_t... Is>
struct S<N, std::index_sequence<Is...>>{
std::array<int, N> matrices;
template <class T>
void foo(typer<const T&, Is>... args) {
int dummy[] = { ((matrices[Is] = args), void(), 0)... };
static_cast<void>(dummy);
}
};
int main() {
S<3> s;
s.foo(1, 2, 3);
}
您可以使您的函数可变,但只接受正确数量的参数。它看起来像这样:
template <std::size_t N>
struct system {
template<typename... Ts>
auto fun(Ts&&... ts) -> std::enable_if_t<(N == sizeof...(Ts))> {
// function content
}
private:
std::array<cv::Mat, N> matrices;
};
如果参数数量等于N
.