简体   繁体   English

“模拟”偏函数模板特化?

[英]“Simulate” Partial Function Template Specialization?

I know that partial template specialization does not hold for functions.我知道部分模板特化不适用于函数。 But is there any way to achieve something similar?但是有什么方法可以实现类似的目标吗? My use case is quite simple, but I'm not sure what's the best way to solve it.我的用例非常简单,但我不确定解决它的最佳方法是什么。

Let's say I'm writing a function that takes in an STL container:假设我正在编写一个接收 STL 容器的函数:

template<typename T>
void doSomething(T& container) {
    // do something here
}

Now, I want a different definition for this function when std::forward_list and std::list are passed in.现在,当std::forward_liststd::list被传std::forward_list ,我想要这个函数的不同定义。

At first I thought perhaps I can overload the function like this:起初我想也许我可以像这样重载函数:

// overload for std::list
template<typename T>
void insertionCppStl(std::list<T>& container) {
    // do seomthing here for list
}

But that would mean I need to do the same overload for std::forward_list as well.但这意味着我也需要对std::forward_list执行相同的重载。 Which is not ideal at all.这一点都不理想。

Is there any way to overload a function for two different input types?有没有办法为两种不同的输入类型重载一个函数? Looking for answers for C++17, but C++20 answer is welcomed as well.寻找 C++17 的答案,但也欢迎 C++20 的答案。

Not a great solution but...不是一个很好的解决方案,但是......

template <template <typename...> class C, typename T>
std::enable_if_t<std::is_same_v<C<T>, std::list<T>>
              || std::is_same_v<C<T>, std::forward_list<T>>>
    insertionCppStl (C<T> & container) {
    // do seomthing here for list
}

(caution: code not tested) (注意:代码未经测试)

As pointed by Daniel Langr (thanks!) this works only for lists with standard allocator, so for std::list<T> and std::forward_list<T> , not for std::list<T, A> and std::forward_list<T, A> where A is an allocator different from std::allocator<T> .正如 Daniel Langr 所指出的(谢谢!)这仅适用于具有标准分配器的列表,因此对于std::list<T>std::forward_list<T> ,不适用于std::list<T, A>std::forward_list<T, A>其中A是不同于std::allocator<T>

This can be enough for you, or not, depending from your needs.这对您来说是否足够,取决于您的需要。

A more generic solution can take in count also the allocator一个更通用的解决方案也可以考虑分配器

template <template <typename...> class C, typename T, typename A>
std::enable_if_t<std::is_same_v<C<T, A>, std::list<T, A>>
              || std::is_same_v<C<T, A>, std::forward_list<T, A>>>
    insertionCppStl (C<T, A> & container) {
    // do seomthing here for list
}

Obviously this works only for std::list and std::forward_list .显然这仅适用于std::liststd::forward_list

As Barry pointed in a comment (thanks!), a similar solution can be implemented when you have two (three, four...) types with something in common (in this case: template types with compatible signatures) but isn't a general solution.正如 Barry 在评论中指出的(谢谢!),当您有两个(三个、四个……)类型具有共同点(在这种情况下:具有兼容签名的模板类型)但不是一个一般解决方案。

Unfortunately I don't see a trivial general solution... I propose the development of a specific type_traits to select the accepted types for a specific version of the function.不幸的是,我没有看到一个简单的通用解决方案......我建议开发一个特定的 type_traits 来为函数的特定版本选择可接受的类型。

For example: if you want a specific version for std::list s, std::forward_list s and std::array s, you can write something as follows例如:如果您想要std::list s、 std::forward_list s 和std::array s 的特定版本,您可以编写如下内容

template <typename>
struct specific_foo : public std::false_type
 { };

template <typename T, typename A>
struct specific_foo<std::list<T, A>> : public std::true_type
 { };

template <typename T, typename A>
struct specific_foo<std::forward_list<T, A>> : public std::true_type
 { };

template <typename T, std::size_t N>
struct specific_foo<std::array<T, N>> : public std::true_type
 { };

Then two version of the foo() function: the specific version (receiving a std::true_type as second argument) and a generic one (receiving a std::false_type然后是foo()函数的两个版本:特定版本(接收std::true_type作为第二个参数)和通用版本(接收std::false_type

template <typename T>
void foo (T const &, std::false_type)
 { std::cout << "generic version" << std::endl; }

template <typename T>
void foo (T const &, std::true_type)
 { std::cout << "specific version" << std::endl; }

Now you need a tag-dispatching version of foo() that select the correct type for the second argument现在你需要一个标签调度版本的foo()来为第二个参数选择正确的类型

template <typename T>
void foo (T const & t)
 { foo(t, specific_foo<T>{}); }

The following is a full compiling example下面是一个完整的编译示例

#include <list>
#include <array>
#include <vector>
#include <iostream>
#include <type_traits>
#include <forward_list>

template <typename>
struct specific_foo : public std::false_type
 { };

template <typename T, typename A>
struct specific_foo<std::list<T, A>> : public std::true_type
 { };

template <typename T, typename A>
struct specific_foo<std::forward_list<T, A>> : public std::true_type
 { };

template <typename T, std::size_t N>
struct specific_foo<std::array<T, N>> : public std::true_type
 { };

template <typename T>
void foo (T const &, std::false_type)
 { std::cout << "generic version" << std::endl; }

template <typename T>
void foo (T const &, std::true_type)
 { std::cout << "specific version" << std::endl; }

template <typename T>
void foo (T const & t)
 { foo(t, specific_foo<T>{}); }

int main ()
 {
   foo(0);                             // print "generic version"
   foo(std::list<int>{});              // print "specific version"
   foo(std::forward_list<long>{});     // print "specific version"
   foo(std::array<long long, 42u>{});  // print "specific version"
   foo(std::vector<char>{});           // print "generic version"
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM