2017-05-06 29 views
1

我有一个问题,我所定义的模板类,以应付不同尺寸的系统作为如下:自动生成函数标题,可变参数模板

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>' 

而且我想这头功能将被​​自动生成基于模板参数N。我试图使用可变模板,但没有发财。

+1

我不是100%确定你想要达到的目标,但是这种方法似乎是错误的IMO。你可能会用更好的运气来自动生成代码(例如:一个小脚本) – UnholySheep

回答

1

如果你可以基于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!");  
    } 
}; 

我的静态断言,而除非你打算有一个名为另一个成员函数,因为这是极不可能会有所作为,如果不是让,让事情变得简单(这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得到了我们想要的。无论是包装中的所有类型是否相同,如果它们相同,我们都可以访问常见类型。一旦我们有一个共同的类型,已验证的大小,我们可以用包来初始化了一个数组和循环,所以我们不必继续做我们的函数中恼人的可变参数编程风格:

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或其他类型时,你会习惯隐式转换,它会失败。不过,希望这可以帮助你继续下去。现场示例:http://coliru.stacked-crooked.com/a/08ac23da33deb8ef

+0

这是我正在寻找的解决方案。我对可变参数模板的第一次尝试是一团糟。不过,对于std :: reference_wrapper和更复杂的模板类型,我遇到了一些麻烦。无论如何,谢谢! – thewoz

1

一种可能的解决方案可以定义函数的类的身体内部(顺便:避免名称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脚本来生成代码。

+0

对不起,我知道我的问题不太清楚。我也认为shell脚本可能是解决方案。无论如何,我也喜欢你的解决方案,但为了避免指定不同的fun()函数,@ nir解决方案运行良好。 – thewoz

3

我相信你也可以使foo更通用使用integer_sequence和别名模板。(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); 
} 

[live demo]

+0

这肯定比我的解决方案更好,利用N是已知的事实并且不需要推断。 –

+0

@NirFriedman另一方面,它确实需要一个constexpr索引背景/实验,可能乍一看并不明显... –

+1

虽然是更优雅。恕我直言,它是“很明显,一旦你已经看到它”的脉络。尽管如此,我并没有真正看到将其应用于免费函数的非常好的方法。看起来你必须转发到一个实现函数,但这是相当不利的,因为它没有正确安装。 –

1

你可以让你的函数可变参数,但只接受参数的权数。它应该是这样的:

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