两个c++程序有相同的问题,但一个编译并链接,另一个出错

2exbekwf  于 2023-01-14  发布在  其他
关注(0)|答案(2)|浏览(115)

有两个c++程序。一个简单,另一个有点复杂。但都有同样的问题。简单的程序有以下文件。foo.h:

class foo{  
static const int array[3];  
};    
const int foo::array[3] = { 1, 2, 3 };     <-------- Here is the line causing the error.

foo.cc:

#include "foo.h"

main.cc:

#include "foo.h"

int main()
{
}

同时使用以下命令编译和链接:

clang++ -c *.cc -std=c++17
clang++ *.o -o a.out -std=c++17

它报告以下错误:

main.o:(.rodata+0x0): multiple definition of `foo::array'
foo.o:(.rodata+0x0): first defined here
clang-14: error: linker command failed with exit code 1 (use -v to see invocation)

对于复杂系统,具有以下文件. t_a.h:

#pragma once
#include "t_b.h"

class TA : public TB,
                    public TIT<TB, TA> {
public:
  static const char* name() { return "TA"; }
};

t_B.h:

#pragma once
#include "t_r.h"

class TB {

  TI<TB> t_i() const { return t_i_; }

 private:
  template <typename T, typename U>
  friend class TIT;
  TI<TB> t_i_{TI<TB>::kUkT};

};

t_i.h:

#pragma once

#include <string>
#include <stdint.h>

template <typename BaseT>
class TR;

template <typename BaseT>
class TI {
 public:
  const std::string& name() const;

  int8_t id() const { return id_; }

  bool operator==(TI other) const { return id_ == other.id(); }
  bool operator!=(TI other) const { return id_ != other.id(); }

  static const TI kUkT;

 private:
  friend class TR<BaseT>;
  explicit TI(int8_t id) : id_(id) {}
  int8_t id_;
};

template <typename BaseT, typename DerivedT>
class TIT {
 public:
  static const TI<BaseT> kT;
  TIT() {
    static_cast<BaseT*>(static_cast<DerivedT*>(this))->t_i_ = kT;
  }
  static bool classof(const BaseT* obj) { return obj->t_i() == kT; }
};

template <typename BaseT>
TI<BaseT> RST(const std::string& t);

template <typename BaseT, typename DerivedT>
const TI<BaseT> TIT<BaseT, DerivedT>::kT =
    RST<BaseT>(DerivedT::name());            <-------- This block of code should cause a similar error, but it does not.

t_r.h:

#pragma once

#include <cassert>
#include <map>
#include <mutex>
#include <string>
#include <vector>

#include "t_i.h"

template <typename BaseT>
class TR {
 public:
  TR(const TR&) = delete;
  TR& operator=(const TR&) = delete;

  static TR& GI();

  TI<BaseT> RT(const std::string& t);
  const std::string& GTN(TI<BaseT> i) const;

 private:
  TR() = default;
  mutable std::mutex mutex_;
  std::vector<std::string> names_;
  std::map<std::string, int8_t> name_to_id_;
};

template <typename BaseT>
TR<BaseT>& TR<BaseT>::GI() {
  static TR<BaseT> r;
  return r;
}

template <typename BaseT>
TI<BaseT> TR<BaseT>::RT(const std::string& t) {
  std::lock_guard<std::mutex> guard(mutex_);
  assert(name_to_id_.find(t) == name_to_id_.end());
  assert(names_.size() < static_cast<decltype(names_.size())>(
                             std::numeric_limits<int8_t>::max()));
  int8_t id = static_cast<int8_t>(names_.size());
  names_.emplace_back(t);
  name_to_id_[t] = id;
  return TI<BaseT>(id);
}

template <typename BaseT>
const std::string& TR<BaseT>::GTN(
    TI<BaseT> info) const {
  std::lock_guard<std::mutex> guard(mutex_);
  int8_t id = info.id();
  assert(id >= 0);
  assert(static_cast<size_t>(id) < names_.size());
  return names_[id];
}

template <typename BaseT>
TI<BaseT> RST(const std::string& type) {
  return TR<BaseT>::GI().RT(type);
}

template <typename BaseT>
const std::string& TI<BaseT>::name() const {
  return TR<BaseT>::GI().GTN(*this);
}

template <typename BaseT>
const TI<BaseT> TI<BaseT>::kUkT =
    RST<BaseT>("Uk");

使用_t_i_1.cc:

#include "t_a.h"

TIT<TB, TA> test_class_1;

使用_t_i_2.cc:

#include "t_a.h"

int main() {
  TIT<TB, TA> test_class_2;
}

当通过以下命令编译和链接时:

clang++ -c *.cc -std=c++17
clang++ *.o -o a.out -std=c++17

没有出现错误。是什么原因导致两个程序都存在同样的语法错误,而一个报告错误,而另一个没有?有人能解释一下吗?有人能对第二个复杂的程序做一个小的调整,使它也出现同样的错误吗?提前感谢。

mbzjlibv

mbzjlibv1#

这条线

const int foo::array[3] = { 1, 2, 3 };

需要在 * one *. cc文件中,而不是在标头中。只需选择一个

c0vxltue

c0vxltue2#

C++明确允许模板化实体的多个定义:
basic.def.odr#13:
可以有多个定义

  • 类类型([class]),
  • 枚举类型([dcl.enum]),
  • 内联函数或变量([dcl.inline]),
    *模板化实体([临时预处理]),
  • 参数的默认实参(对于给定作用域中的函数)([dcl.fct.default]),或
  • 缺省模板参数([temp.param])

因此,不会导致多重定义错误。

相关问题