C++模板元编程,"static if"解决方法 - 可以改进吗?

C++ template metaprogramming, "static if" workaround - can it be improved?

本文关键字:方法 if 编程 C++ static 解决      更新时间:2023-10-16

我有一个函数,它扫描用户的文件系统,用路径填充向量,然后对其进行排序或不排序。由于用户应该能够在编译时决定是否要对向量进行排序,因此我使用模板和helper类来代替非常需要的(但不存在的)"静态"。

考虑以下代码:

enum class Sort{Alphabetic, Unsorted};  
template<Sort TS> struct SortHelper;
template<> struct SortHelper<Sort::Alphabetic>
{
    static void sort(vector<string>& mTarget) { sort(begin(mTarget), end(mTarget)); }
};
template<> struct SortHelper<Sort::Unsorted>
{
    static void sort(vector<string>&) { }
};
template<Sort TS> struct DoSomethingHelper
{
    static void(vector<string>& mTarget)
    {
         // do something with mTarget
         SortHelper<TS>::sort(mTarget);
    }   
};

我上面写的代码比原始代码大大简化了,它接受多个模板参数,允许用户在编译时进一步定制函数的结果。

是否有替代使用所有这些助手类的方法?它真的很乱,很难阅读。

理想情况下,这是我想写的:

enum class Sort{Alphabetic, Unsorted};  
template<Sort TS> struct DoSomethingHelper
{
    static void(vector<string>& mTarget)
    {
         // do something with mTarget
         static_if(TS == Sort::Unsorted) { /* do nothing */ }
         static_if(TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); }
    }   
};

由于您的值在编译时是已知的(非模板类型参数),您可以完美地编写"正常" if:

template<Sort TS>
void someFunction(vector<string>& mTarget)
{
     if (TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); }
     // else if (TS == Sort::Unsorted) {}
}

编译器将执行常量折叠死代码消除(当然,如果启用了这些优化),结果将与使用假设的static_if完全相同。

恐怕对static_if的用法存在误解。

当然,您可以使用static_if(或任何您希望的技巧)来尝试获得一些优化,但这不是它的首要目标。

static_if的第一个目标是语义上的。让我用std::advance来演示一下。std::advance的典型实现将在编译时使用类型切换,在O(1)实现(用于随机访问迭代器)和O(n)实现(用于其他)之间进行选择:
template <typename It, typename D>
void advance_impl(It& it, D d, random_access_iterator_tag)
{
    it += d;
}
template <typename It, typename D>
void advance_impl(It& it, D d, bidirectional_iterator_tag)
{
    if (d > D(0)) { for (D i(0); i < d; ++i) { ++it; } }
    else          { for (D i(0); i > d; --i) { --it; } }
}
template <typename It, typename D>
void advance_impl(It& it, D d, input_iterator_tag)
{
    for (D i(0); i < d; ++i) { ++it; }
}

最后:

template <typename It, typename D>
void advance(It& it, D d)
{
    typename std::iterator_traits<It>::iterator_category c;
    advance_impl(it, d, c);
}

在这种情况下为什么不使用if呢?因为它无法编译。

  • 双向迭代器不支持+=
  • 输入迭代器(或前向迭代器)不支持--

因此,实现该功能的惟一方法是静态地只使用给定类型上的可用操作分派给函数。

模板专门化呢?

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
enum class Sort {
    Alphabetic, 
    Unsorted
};
template<Sort TS> struct DoSomethingHelper {
    static void someFunction(vector<string>& mTarget)
    {}  
};
template<> struct DoSomethingHelper<Sort::Unsorted> {
    static void someFunction(vector<string>& mTarget) {
    }  
};
template<> struct DoSomethingHelper<Sort::Alphabetic> {
    static void someFunction(vector<string>& mTarget) {
        sort(begin(mTarget), end(mTarget));
    }  
};
int main() {
    vector<string> v = {{"foo", "bar", "foo2", "superman", ".."}};
    DoSomethingHelper<Sort::Alphabetic> helper;
    helper.someFunction(v);
    for (string& s : v) {
        cout << s << endl;
    }
    return 0;
}

编辑:我是一个白痴。