如何专门针对指向复数值的迭代器的算法?
How can I specialize an algorithm for iterators that point to complex values?
我正在尝试编写一种适用于迭代器的算法(类似于 STL 算法)但是我需要编写算法的专门化以在迭代器指向 complex
值与常规 double
值。
这是一个基本示例:
#include <complex>
#include <iostream>
#include <vector>
using namespace std;
template <typename InputIt>
void DoSomething(InputIt first, InputIt last)
{
cout << "Regular Double" << endl;
for (; first != last; ++first)
{
cout << *first << endl;
}
}
//// Specialize the template for containers holding complex values
//template <typename InputItToComplex>
//void DoSomething(InputItToComplex first, InputItToComplex last)
//{
// cout << "Complex Double" << endl;
//
// for (; first != last; ++first)
// {
// cout << *first << endl;
// }
//}
int main()
{
vector<double> values = { 1.5, 2.2, 3.1, 4.5, 5.1, 6.9, 7.1, 8.9 };
// Call the regular template
DoSomething(values.begin(), values.end());
vector<complex<double>> cplx_values = { complex<double>{1.4, 2.1}, complex<double>{2.2, 3.5}, complex<double>{7.1, 9.1 } };
// Need to call the complex specialized version of the template
DoSomething(cplx_values.begin(), cplx_values.end());
}
如何编写专业化版本,以便在我有 complex
值的容器时自动使用 complex
专业化版本?上面注释掉的代码显然不起作用,因为它只会导致两个不明确的定义。
您可以使用 SFINAE and std::iterator_traits
来约束 "specialized" 模板。您还需要一个助手来检查迭代器特征返回的 value_type
是否是 std::complex
的特化。该代码是
template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};
template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};
并由 Quentin
撰写
使用它你会
template <typename InputIt,
std::enable_if_t<!is_specialization<typename std::iterator_traits<InputIt>::value_type, std::complex>::value, bool> = true>
void DoSomething(InputIt first, InputIt last)
{
cout << "Regular Double" << endl;
for (; first != last; ++first)
{
cout << *first << endl;
}
}
template <typename InputItToComplex,
std::enable_if_t<is_specialization<typename std::iterator_traits<InputItToComplex>::value_type, std::complex>::value, bool> = true>
void DoSomething(InputItToComplex first, InputItToComplex last)
{
cout << "Complex Double" << endl;
for (; first != last; ++first)
{
cout << *first << endl;
}
}
作为 SFINAE 的替代方案(但仍然需要特性),在 C++17 中,您可以使用 if constexpr
(即使常规 if
可以在当前代码段中使用):
template <typename InputIt>
void DoSomething(InputIt first, InputIt last)
{
if constexpr (is_specialization<typename std::iterator_traits<InputIt>::value_type,
std::complex>::value) {
std::cout << "Complex Double" << std::endl;
} else {
std::cout << "Regular Double" << std::endl;
}
for (; first != last; ++first) {
std::cout << *first << std::endl;
}
}
我正在尝试编写一种适用于迭代器的算法(类似于 STL 算法)但是我需要编写算法的专门化以在迭代器指向 complex
值与常规 double
值。
这是一个基本示例:
#include <complex>
#include <iostream>
#include <vector>
using namespace std;
template <typename InputIt>
void DoSomething(InputIt first, InputIt last)
{
cout << "Regular Double" << endl;
for (; first != last; ++first)
{
cout << *first << endl;
}
}
//// Specialize the template for containers holding complex values
//template <typename InputItToComplex>
//void DoSomething(InputItToComplex first, InputItToComplex last)
//{
// cout << "Complex Double" << endl;
//
// for (; first != last; ++first)
// {
// cout << *first << endl;
// }
//}
int main()
{
vector<double> values = { 1.5, 2.2, 3.1, 4.5, 5.1, 6.9, 7.1, 8.9 };
// Call the regular template
DoSomething(values.begin(), values.end());
vector<complex<double>> cplx_values = { complex<double>{1.4, 2.1}, complex<double>{2.2, 3.5}, complex<double>{7.1, 9.1 } };
// Need to call the complex specialized version of the template
DoSomething(cplx_values.begin(), cplx_values.end());
}
如何编写专业化版本,以便在我有 complex
值的容器时自动使用 complex
专业化版本?上面注释掉的代码显然不起作用,因为它只会导致两个不明确的定义。
您可以使用 SFINAE and std::iterator_traits
来约束 "specialized" 模板。您还需要一个助手来检查迭代器特征返回的 value_type
是否是 std::complex
的特化。该代码是
template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};
template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};
并由 Quentin
使用它你会
template <typename InputIt,
std::enable_if_t<!is_specialization<typename std::iterator_traits<InputIt>::value_type, std::complex>::value, bool> = true>
void DoSomething(InputIt first, InputIt last)
{
cout << "Regular Double" << endl;
for (; first != last; ++first)
{
cout << *first << endl;
}
}
template <typename InputItToComplex,
std::enable_if_t<is_specialization<typename std::iterator_traits<InputItToComplex>::value_type, std::complex>::value, bool> = true>
void DoSomething(InputItToComplex first, InputItToComplex last)
{
cout << "Complex Double" << endl;
for (; first != last; ++first)
{
cout << *first << endl;
}
}
作为 SFINAE 的替代方案(但仍然需要特性),在 C++17 中,您可以使用 if constexpr
(即使常规 if
可以在当前代码段中使用):
template <typename InputIt>
void DoSomething(InputIt first, InputIt last)
{
if constexpr (is_specialization<typename std::iterator_traits<InputIt>::value_type,
std::complex>::value) {
std::cout << "Complex Double" << std::endl;
} else {
std::cout << "Regular Double" << std::endl;
}
for (; first != last; ++first) {
std::cout << *first << std::endl;
}
}