使用enable_if或类似内容的模板结构标签部分专业

时间:2019-02-18 14:57:50

标签: c++ templates c++14

我正在寻找一种使用std :: enable_if或类似方法扩展现有的自定义点的方法,该自定义点的工作方式类似于下面的A<T>专业化(只是一个虚拟示例):

// customisation point structure in external lib
template<typename T>
struct A
{
    typedef T type;
};

//---------------------------------------------
#include <vector>

template <typename T>
concept bool Floating = std::is_floating_point<T>::value;

// specialisation with enable_if style that doesn't require change to external lib
template<Floating T>
struct A<T>
{
    typedef std::vector<T> type;
};

int main()
{
    static_assert(std::is_same<A<int>::type, int>::value, "");
    static_assert(std::is_same<A<float>::type, std::vector<float>>::value, "");

    return 0;
}

问题是我有以下限制:

  • 结构A不能修改为接受两个模板参数template<typename T, typename = void>,因为此结构是在外部库中定义的
  • 不能精简使用概念(有些人认为有必要将其标准化推迟到未来几年...)
  • 不想使用A<type_mod<float>>之类的东西将所有调用站点上的代码弄乱,因为这很丑陋且容易出错(对于宏使用也是如此)
  • 不想编写外部代码生成器

我怀疑是否有可能,但是我记得过去人们说过,不需要精简概念是因为可以用元编程或多或少地模仿它们,所以我希望有人能证明我错了。

1 个答案:

答案 0 :(得分:0)

为确保我正确理解了这个问题,您是否正在寻找与您发布的代码等效的东西,但仅使用C ++ 14(无概念)?

我认为您提到的第一个限制(“结构A不能修改为接受两个模板参数”)是最大的问题。我不知道有什么方法可以在不使用概念的情况下立即为整个类型的整个“类”(例如浮点类型)专门化一个现有的单参数模板。

因此,我认为对您的问题的严格回答是:“不,这不可能。”

如果您可以修改A的第一个声明,那么它会容易得多。就我个人而言,我觉得有时候以“我无法修改此外部库”开头的问题的最佳答案是,“去找出如何修改它,然后再问您一个问题。”

我在下面提供了一种替代解决方案的想法,但是您的问题中缺少太多信息,无法说明它是否对您有用。

我假定此外部库会引入您提供的某些标头,以查看您的专业化,并且每当更改该标头时,您都将重新编译该库。 (如果不是这种情况,请编辑您的问题以更好地解释这种情况。)

在要放置专业化内容的同一标头中,您可以考虑使用一些老式的预处理器技巧作为解决方法。这很丑陋,您必须注意#include语句的顺序,但这可能会为您完成工作:

// customisation point structure in external lib
template<typename T>
struct A
{
    typedef T type;
};

//---------------------------------------------
#include <vector>

template<typename T, bool is_float>
struct Av2impl
{
    typedef T type;
};

template<typename T>
struct Av2impl<T, true>
{
    typedef std::vector<T> type;
};

template<typename T>
struct Av2
{
    typedef typename Av2impl<T, std::is_floating_point<T>::value>::type type;
};

// force all code after this point to use Av2 instead of A
#define A Av2

int main()
{
    static_assert(std::is_same<A<int>::type, int>::value, "");
    static_assert(std::is_same<A<float>::type, std::vector<float>>::value, "");

    return 0;
}