依赖模板名称参数替换

时间:2014-02-13 15:35:08

标签: c++ templates

我不知道如何解释这个,所以我会给出代码。

我正在尝试编码(为了好玩,也帮助我理解模板元编程)使用C ++模板的数字。

struct Z {
  static constexpr unsigned int n = 0;

  template<typename T>
  using replace = T;
};

template<typename T>
struct S {
  static constexpr unsigned int n = T::n + 1;

  template<typename U>
  // using replace = T::replace<U>;
  using replace = typename T::template replace<U>;
};

所以,我尝试了using replace = T::replace<U>,这真的不起作用,我不知道为什么(我正在使用GCC), 如果有人可以解释为什么要这样做我会很感激我 (见下面的链接)。当我尝试使用Clang进行编译时,它给了我一个很好的错误消息:

首先,use 'template' keyword to treat 'replace' as a dependent template name,然后template argument for template type parameter must be a type; did you forget 'typename'? ...

然后我设法让using replace = typename T::template replace<U>编译,这似乎是合法的。

但我真正需要的是像S<T::replace<U>>这样的东西,我找不到工作方法。

我也尝试将其更改为T::replace<U>::succ,并将succ定义为S<Z>上的ZS<S<T>>上的S,但是我无法让它工作......

有什么想法吗? :(

1 个答案:

答案 0 :(得分:1)

教会数字的精度为2;它们使用仿函数和值并将仿函数n应用于值。在元编程中,这可以表示为具有2个模板参数的模板,第一个是模板模板参数:

struct Z {
  template<template<typename> class F, typename x>
  using replace = x;
};

template<typename T>
struct S {
  template<template<typename> class F, typename x>
  using replace = F<typename T::template replace<F, x>>;
};

我们可以使用F作为integral_constant s上的后继函数来测试它(它们不是lambda演算中的值,但它并不关心它):

#include <type_traits>
template<typename N> using s = typename std::integral_constant<typename N::value_type, N::value + 1>;
static_assert(S<S<Z>>::replace<s, std::integral_constant<int, 2>>::value == 4, "arithmetic!");

如果你想讨好replace,语法会变得更复杂:

struct Z {
  template<template<typename> class F> struct replace {
    template<typename x> using apply = x;
  };
};

template<typename T>
struct S {
  template<template<typename> class F> struct replace {
    template<typename x> using apply = F<typename T::template replace<F>::template apply<x>>;
  };
};

严格地说,通过获取模板模板参数,我们引入了无类型lambda演算中不存在的区别(函子和值之间)。解决这个问题的方法是让我们的函子作为包含应用程序机制的typename参数:

struct Z {
  template<typename F> struct replace {
    template<typename x> using apply = x;
  };
};

template<typename T>
struct S {
  template<typename F> struct replace {
    template<typename x> using apply = typename F::template apply<typename T::template replace<F>::template apply<x>>;
  };
};

示威:

#include <type_traits>
struct s { template<typename N> using apply = typename std::integral_constant<typename N::value_type, N::value + 1>; };
static_assert(S<S<Z>>::replace<s>::template apply<std::integral_constant<int, 2>>::value == 4, "arithmetic!");