需要一些清晰的代码来实现模板吗 我正在使用一些模板类和方法(几乎只是模板)来处理C++库。为了更容易阅读,我想将声明和实现分开。但有时它会变得疯狂: template < typename T > class Foo { template < typename U > class SubFoo { }; template < typename U > SubFoo<U> bar(); }; template < typename T > template < typename U > Foo<T>::SubFoo<U> Foo<T>::bar() {} 模板 福班{ 模板 类子对象{ }; 模板 subfo-bar(); }; 模板 模板 Foo::SubFoo Foo::bar(){}

需要一些清晰的代码来实现模板吗 我正在使用一些模板类和方法(几乎只是模板)来处理C++库。为了更容易阅读,我想将声明和实现分开。但有时它会变得疯狂: template < typename T > class Foo { template < typename U > class SubFoo { }; template < typename U > SubFoo<U> bar(); }; template < typename T > template < typename U > Foo<T>::SubFoo<U> Foo<T>::bar() {} 模板 福班{ 模板 类子对象{ }; 模板 subfo-bar(); }; 模板 模板 Foo::SubFoo Foo::bar(){},c++,templates,C++,Templates,这是一个非常简单的例子。。。 因此,如果您有一些别名来改进此功能,或者有任何编码样式指南。 我和NeoVim一起工作,所以如果你知道一些可以让生活更轻松的插件,那也很好 PS:我没有任何C++限制。 事实上,我忘记了一些基本的东西,比如宏,存在于C++中。 #define Class Foo<T> template < typename T > template < typename U > Class::SubFoo<U> Class::ba

这是一个非常简单的例子。。。 因此,如果您有一些别名来改进此功能,或者有任何编码样式指南。 我和NeoVim一起工作,所以如果你知道一些可以让生活更轻松的插件,那也很好

PS:我没有任何C++限制。


事实上,我忘记了一些基本的东西,比如宏,存在于C++中。
#define Class Foo<T>

template < typename T >
template < typename U >
Class::SubFoo<U> Class::bar() {}
#定义类Foo
模板
模板
类::子类::bar(){}
不是很好,但还是更好。是否要在没有宏的情况下执行该操作

我非常喜欢描述类和源文件的头文件,您可以在其中找到实现。我认为同一个文件中的所有内容都是一团糟

也许你是对的,当你说“同一个文件中的所有东西都是一团糟”时,但是使用模板结构/类确实很难避免

下面是一个简单的例子

假设您有三个文件

1) 一个标头(“header.h”),其中定义了一个模板结构
foo
,其中包含一个已定义但未实现的构造函数

template <typename T>
struct foo
 { 
   foo ();
 };
#include "header.h"

template <typename T>
foo<T>::foo ()
 { }
3) 一个cpp文件(“b.cpp”),其中实现了
foo
构造函数

template <typename T>
struct foo
 { 
   foo ();
 };
#include "header.h"

template <typename T>
foo<T>::foo ()
 { }
但是当您想在不同的源文件中使用
foo
时,您必须记住相应地更新“b.cpp”

只有当您想要控制
foo
可以实现的确切类型集时,这才是一个好的解决方案(IMHO)


通常(IMHO)最好的解决方案是在头中实现所有模板结构/类,而(IMHO,像往常一样)在结构/类的主体中实现它更为清晰,我不确定这是否是个好主意,所以现在我不接受答案

让我们举一个真实的例子(一个小的,不用担心):

template
模板
DefaultManager::迭代器DefaultManager::begin(){
无符号整数i;
对于(i=0;
!iterator::is_Valid(m_pool[i].data);
++i) );
返回std::move(迭代器(i));
}
模板
模板
DefaultManager::迭代器DefaultManager::end(){
无符号整数i;
对于(i=m_pool.size();
!iterator::is_Valid(m_pool[i].data);
--i) );
返回std::move(迭代器(i));
}

#定义模板参数typename对象,布尔共享
#定义类DefaultManager
#定义迭代器类::迭代器
模板<模板参数>
模板
迭代器类::begin(){
无符号整数i;
对于(i=0;
!ITERATOR::is_Valid(m_pool[i].data);
++i) );
返回std::move(迭代器(i));
}
模板<模板参数>
模板
迭代器类::end(){
无符号整数i;
对于(i=m_pool.size();
!ITERATOR::is_Valid(m_pool[i].data);
--i) );
返回std::move(迭代器(i));
}
现在你会说,在程序中创建这么多宏是一个真正的问题,我至少应该在宏名称中添加一个名称空间。但对于模块,这是不需要的,因为默认情况下不会导出宏


我认为这是一个小小的改进,但可能不是一个好的改进。

因此,分离实现并不会让您“更容易阅读”。解决问题的常用方法不是尝试这个方法。如果你想读代码,请不要用C++编写。如果你使用neovim,很难找到一个好的自动格式化插件。但是我真的很喜欢描述类的头文件和可以找到实现的源文件。我认为同一个文件中的每一个都是一团糟。你不必像你那样逐行写模板,也可以编写模板< Type NeNT,Type NeNeU>无法从其声明中拆分模板定义是C++中的一个古老问题。唯一的理论解决方案是<>代码>导出< /Cord>关键字,但是几乎没有编译器实现它,它不会做人们期望的,它已经从C++中删除了。接受它吧。最重要的是,你的库的文档很容易阅读,当然还有它使用后产生的客户机代码。我知道这一点不用担心。拆分成几个文件只是我有一个.tpp文件,它包含在template.hpp文件的末尾,并且不在类中。这就是我以这种代码结尾的原因。但谢谢你的回答:)我不应该说头文件和源文件,但我不知道怎么说其他的东西。@Mathieuvanevel-对不起:我不知道这对你来说是清楚的:(对不起的是我,因为你花了你的时间:(
template < typename Object, bool Shared >
  template < ECS_INT Filter >
DefaultManager<Object, Shared>::iterator<Filter>  DefaultManager<Object, Shared>::begin() {

  unsigned int i;
  for (i = 0;
       !iterator<Filter>::is_Valid(m_pool[i].data);
       ++i);
  return std::move(iterator<Filter>(i));
}

template < typename Object, bool Shared >
  template < ECS_INT Filter >
DefaultManager<Object, Shared>::iterator<Filter>  DefaultManager<Object, Shared>::end() {

  unsigned int i;
  for (i = m_pool.size();
       !iterator<Filter>::is_Valid(m_pool[i].data);
       --i);
  return std::move(iterator<Filter>(i));
}
#define TEMPLATE_ARGS  typename Object, bool Shared
#define CLASS    DefaultManager<Object, Shared>
#define ITERATOR CLASS::iterator<Filter>

template < TEMPLATE_ARGS >
  template < ECS_INT Filter >
ITERATOR  CLASS::begin() {

  unsigned int i;
  for (i = 0;
       !ITERATOR::is_Valid(m_pool[i].data);
       ++i);
  return std::move(ITERATOR(i));
}

template < TEMPLATE_ARGS >
  template < ECS_INT Filter >
ITERATOR  CLASS::end() {

  unsigned int i;
  for (i = m_pool.size();
       !ITERATOR::is_Valid(m_pool[i].data);
       --i);
  return std::move(ITERATOR(i));
}