“……的多重定义”模板函数的完全特化的错误

发布于 2024-10-08 17:17:03 字数 3023 浏览 1 评论 0原文


我有一个配置项目:

./main.cpp  
./type_traints/TypeTraints.cpp
./type_traints/TypeTraints.hpp
./type_traints/chapter_20.hpp

./type_traints/CMakeLists.txt 文件是:

 cmake_minimum_required (VERSION 2.8)
 add_library(chapter_20 TypeTraints.cpp)

./CMakeLists.txt 如下:

cmake_minimum_required (VERSION 2.8)
project (mpl)

add_subdirectory(type_traints)
include_directories(type_traints)
link_directories(type_traints)

add_executable (mpl main.cpp)
target_link_libraries(mpl chapter_20)

文件的相关部分(大部分包含省略)包括:
./type_traints/chapter_20.hpp

#ifndef CHAPTER_20_GUARD
#define CHAPTER_20_GUARD
#include <TypeTraints.hpp>

void chapter_20() {
  test_23();
}   
#endif //CHAPTER_20_GUARD

./type_traints/TypeTraints.hpp

#ifndef TYPE_TRAINTS_GUARD
#define TYPE_TRAINTS_GUARD
namespace details {

  template<class T> const char* class2name() {
    return "unknown";
  };

  template<> const char* class2name<int>() {
    return "int";
  };
}

template<class T>
class type_descriptor {
  friend std::ostream& operator << (std::ostream& stream, 
                                    const type_descriptor<T>& desc) {
    stream << desc.getName();
    return stream;
  }

public:
  std::string getName() const;  
};

template<class T>
std::string type_descriptor<T>::getName() const {
  return details::class2name<T>();
}

void test_23();    
#endif // TYPE_TRAINTS_GUARD

./type_traints/TypeTraints.cpp

#include<TypeTraints.hpp>

void test_23() {
  cout << type_descriptor<int>() << endl;
}

和 ./main.cpp

#include <chapter_20.hpp>

int main(int argc, char* argv[]) {
chapter_20();
  return 0;
}

项目编译但无法链接:

[ 50%] Building CXX object type_traints/CMakeFiles/chapter_20.dir/TypeTraints.cpp.o
Linking CXX static library libchapter_20.a
[ 50%] Built target chapter_20
[100%] Building CXX object CMakeFiles/mpl.dir/main.cpp.o
Linking CXX executable mpl
type_traints/libchapter_20.a(TypeTraints.cpp.o): In function `char const* details::cl
ass2name<int>()':                                                                   
/home/marcin/Projects/mpl/type_traints/TypeTraints.hpp:312: multiple definition of `c
har const* details::class2name<int>()'                                              
CMakeFiles/mpl.dir/main.cpp.o:/home/marcin/Projects/mpl/type_traints/TypeTraints.hpp:
312: first defined here                                                             
collect2: ld returned 1 exit status
make[2]: *** [mpl] Błąd 1
make[1]: *** [CMakeFiles/mpl.dir/all] Error 2
make: *** [all] Error 2
23:56:20@marcin-laptop ~/P

如果我删除 class2name 专业化 (class2name< ;int>()) 来自 TypeTraints.hpp 并仅使用通用实现。

有人知道这是为什么吗?我是否错过配置 cmake 文件?

I have a project with configuration:

./main.cpp  
./type_traints/TypeTraints.cpp
./type_traints/TypeTraints.hpp
./type_traints/chapter_20.hpp

The ./type_traints/CMakeLists.txt file is:

 cmake_minimum_required (VERSION 2.8)
 add_library(chapter_20 TypeTraints.cpp)

and the ./CMakeLists.txt follows:

cmake_minimum_required (VERSION 2.8)
project (mpl)

add_subdirectory(type_traints)
include_directories(type_traints)
link_directories(type_traints)

add_executable (mpl main.cpp)
target_link_libraries(mpl chapter_20)

Relevant parts of files (most includes omitted) include:
./type_traints/chapter_20.hpp

#ifndef CHAPTER_20_GUARD
#define CHAPTER_20_GUARD
#include <TypeTraints.hpp>

void chapter_20() {
  test_23();
}   
#endif //CHAPTER_20_GUARD

./type_traints/TypeTraints.hpp

#ifndef TYPE_TRAINTS_GUARD
#define TYPE_TRAINTS_GUARD
namespace details {

  template<class T> const char* class2name() {
    return "unknown";
  };

  template<> const char* class2name<int>() {
    return "int";
  };
}

template<class T>
class type_descriptor {
  friend std::ostream& operator << (std::ostream& stream, 
                                    const type_descriptor<T>& desc) {
    stream << desc.getName();
    return stream;
  }

public:
  std::string getName() const;  
};

template<class T>
std::string type_descriptor<T>::getName() const {
  return details::class2name<T>();
}

void test_23();    
#endif // TYPE_TRAINTS_GUARD

./type_traints/TypeTraints.cpp

#include<TypeTraints.hpp>

void test_23() {
  cout << type_descriptor<int>() << endl;
}

and ./main.cpp

#include <chapter_20.hpp>

int main(int argc, char* argv[]) {
chapter_20();
  return 0;
}

The project compiles but fails to link:

[ 50%] Building CXX object type_traints/CMakeFiles/chapter_20.dir/TypeTraints.cpp.o
Linking CXX static library libchapter_20.a
[ 50%] Built target chapter_20
[100%] Building CXX object CMakeFiles/mpl.dir/main.cpp.o
Linking CXX executable mpl
type_traints/libchapter_20.a(TypeTraints.cpp.o): In function `char const* details::cl
ass2name<int>()':                                                                   
/home/marcin/Projects/mpl/type_traints/TypeTraints.hpp:312: multiple definition of `c
har const* details::class2name<int>()'                                              
CMakeFiles/mpl.dir/main.cpp.o:/home/marcin/Projects/mpl/type_traints/TypeTraints.hpp:
312: first defined here                                                             
collect2: ld returned 1 exit status
make[2]: *** [mpl] Błąd 1
make[1]: *** [CMakeFiles/mpl.dir/all] Error 2
make: *** [all] Error 2
23:56:20@marcin-laptop ~/P

The project links fine if I remove the class2name specialization (class2name<int>()) from TypeTraints.hpp and use only the generic implementation.

Does anybody have an idea Why is that? Did I miss-configure cmake files?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

樱花坊 2024-10-15 17:17:03

简而言之:显式(即完全)专用的模板函数不再是模板。它是一个普通函数,并且遵循普通函数的单一定义规则。

换句话说,您无法在头文件中明确定义专用函数模板。这样做会导致 ODR 违规。

只要模板至少依赖于一个参数,它就是模板。即部分特化可以在头文件中定义(因为它们仍然模板)。 显式(即完整)特化只能在头文件中声明,但必须在实现文件中定义,就像普通函数一样。

In short: an explicitly (i.e. fully) specialized template function is no longer a template. It is an ordinary function and it obeys One Definition Rule for ordinary functions.

In other words you can't define explicitly specialized function templates in header file. Doing so will result in ODR violations.

A template is a template only as long as it depends on at least one parameter. I.e. partial specializations can be defined in header files (since they are still templates). Explicit (i.e. full) specializations can only be declared in header files, but have to be defined in implementation files, just like ordinary functions.

翻身的咸鱼 2024-10-15 17:17:03

这违反了单一定义规则:

可以有多个定义
属于类别类型(第 9 条),
枚举类型(7.2),内联
具有外部联动功能
(7.1.2)、类模板(第 14 条)、
非静态函数模板(14.5.5),
类模板的静态数据成员
(14.5.1.3)、类的成员函数
模板 (14.5.1.1) 或模板
一些模板的专业化
未指定参数
(14.7,
14.5.4)在程序中,前提是每个定义出现在不同的
翻译单位,并提供
定义满足以下条件
要求。

class2name 模板函数的显式特化不属于这些情况。因此,我相信将 class2name() 定义移动到实现文件中应该可以解决该问题。我还认为您应该看看“为什么不专门化函数模板?”

This is a violation of the one definition rule :

There can be more than one definition
of a class type (clause 9),
enumeration type (7.2), inline
function with external linkage
(7.1.2), class template (clause 14),
non-static function template (14.5.5),
static data member of a class template
(14.5.1.3), member function of a class
template (14.5.1.1), or template
specialization for which some template
parameters are not specified
(14.7,
14.5.4) in a program provided that each definition appears in a different
translation unit, and provided the
definitions satisfy the following
requirements.

An explicit specialization of the class2name template function does not fall in any of these cases. For this reason, I believe that moving class2name<int>() definition into an implementation file should fix the issue. I also think you should have a look on "Why not specialize function templates ?".

耳钉梦 2024-10-15 17:17:03

您的文件:

./main.cpp  
./type_traints/TypeTraints.cpp  
./type_traints/TypeTraints.hpp  
./type_traints/chapter_20.hpp

其中 TypeTraints.hpp 直接包含在 TypeTraits.cpp 中,间接包含在 main.cpp 中(通过 Chapter_20.hpp)。但是,您的完整规范模板

 template<> const char* class2name<int>() {
     return "int";
 };

是在 TypeTraints.hpp 中定义的,它存在于两个不同的编译单元(上面的两个 .cpp 文件)中。这两个文件在编译后会链接在一起,这会导致多重定义链接错误。

Your files:

./main.cpp  
./type_traints/TypeTraints.cpp  
./type_traints/TypeTraints.hpp  
./type_traints/chapter_20.hpp

in which TypeTraints.hpp is directly included in TypeTraits.cpp and indirectly included in main.cpp(through chapter_20.hpp). However, you fully specification template

 template<> const char* class2name<int>() {
     return "int";
 };

is defined in TypeTraints.hpp which be existing in two different compilation units(the above two .cpp file). These two files will be linked together after compilation and this cause the multiple definition link error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文