让C ++推导出一个参数定义的类/命名空间的位置

时间:2014-02-26 13:54:42

标签: c++ c++11

此代码编译时没有任何警告或错误,并且可执行。

template<class T>
struct testclass
{
    template<int I>
    class inner {};
    template<int I>
    void f(inner<I> ) {}
};

int main()
{
    testclass<bool> test;
    test.f(testclass<bool>::inner<3>()); // l. 13
    return 0;
}

现在,我想要做的是省略第13行中的testclass::

test.f(inner<3>());

它不起作用。我可以在testclass'定义中添加任何内容,以便我的代码可以使用吗?

允许使用C ++ 11。

3 个答案:

答案 0 :(得分:7)

一般情况下,没有全局编译器标志可以允许这样的推论,因为这会破坏名称范围。

但是,您可以在外部使用typedef(或者在模板的情况下 - 具有类型别名)。在你的情况下,它将是:

template <int I> using inner = testclass::inner<I>;

这必须用全局命名空间编写,而不是testclass

请注意,模板别名 C ++ 11的一项功能

答案 1 :(得分:3)

首先,样板。

索引样板:

template<unsigned... Is> struct indexes {typedef indexes<Is...> type;};
template<unsigned Max, unsigned... Is> struct make_indexes:make_indexes<Max-1, Max-1, Is...> {};
template<unsigned... Is> struct make_indexes<0, Is...>:indexes<Is...> {};

一个助手类,允许代理构造而不命名封闭类:

template<int I, typename... Args>
struct inner_helper {
  std::tuple<Args...> args;
  template<typename T, unsigned... Is>
  T construct(indexes<Is...>) && {
    return { std::forward<Args>(std::get<Is>(args))... };
  }
  template<typename T>
  T construct() && {
    return std::move(*this).template construct<T>( make_indexes<sizeof...(Args)>() );
  }
};

帮助函数,为您提供所需的语法。请注意,inner<3>现在是一个函数调用,而不是在封闭类范围之外创建一个对象:

template<int I, typename... Args>
inner_helper<I, Args...> inner( Args&&... args ) {
  return {std::forward<Args>(args)...};
}

我们用两个重载来增加testclass。一个人使用inner_helper<int, Args...>并使用inner<int>构建Args...,另一个使用inner<int>

template<class T>
struct testclass
{
  template<int I>
  class inner {};
  template<int I>
  void f(inner<I> ) {}
  template<int I, typename... Args>
  void f(inner_helper<I, Args...> h) {
    return f( std::move(h).template construct<inner<I>>() );
  }
};

最后,在使用时请求的语法:

int main()
{
  testclass<bool> test;
  test.f(inner<3>()); // l. 13
  return 0;
}

这使您可以执行所需的语法(inner<3>()),支持使用任意参数(完美转发)构造所述inner<3>,并调用实际的f(inner<I>)方法。 / p>

它确实要求inner<I>可以移动构造,并且可以从inner<I>的参数隐式构造。

我假设inner<I>比你上面使用的类型复杂一点。如果它不复杂,你应该考虑C ++迭代器的SCARY技术,其中迭代器(内部类型sortof)实际上是外部类型。

live example

答案 2 :(得分:2)

您不能省略testclass::,因为inner是testclass类的内部类。

您可以做的是更改f功能的签名,使其更简单:

struct testclass
{
    template<int I>
    class inner {};

    template<int I>
    void f1() {
        inner<I> obj;
    }
    template<typename T>
    void f2( T&& )
    {
    }
};

int main()
{
    testclass test;
    test.f1<3>();
    test.f2(testclass::inner<3>());
}