Why do I get weird class method redefinition errors when I compile with Visual C++ 2022?

85 Views Asked by At

I'm trying to write my vector, to realize the function of the one in STL as much as possible. However when I tried to run a test project, Visual Studio told me that, const version of begin(), const version of end(), cbegin() and cend() trigger C2373 errors due to redefinitions.

I'm sure I didn't define these methods twice. Here is a minimal version to reproduce these errors.

#include <algorithm>  //for std::reverse_iterator

template <typename Type>
class vector_iterator;

template <typename Type>
class vector
{
    friend class vector_iterator<Type>;

public:
    // These alies are used as return type.
    using iterator = vector_iterator<Type>;
    using const_iterator = const vector_iterator<Type>;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    constexpr vector() noexcept{}; // simplified constructor

    constexpr vector_iterator<Type> begin() noexcept;
    constexpr const vector_iterator<Type> begin() const noexcept; // causes C2373.
    constexpr const vector_iterator<Type> cbegin() const noexcept; // causes C2373.

    constexpr vector_iterator<Type> end() noexcept;
    constexpr const vector_iterator<Type> end() const noexcept; // causes C2373.
    constexpr const vector_iterator<Type> cend() const noexcept; // causes C2373.

private:
    size_t size_ = 0;
    Type* ptr_data_ = nullptr;
};


// non-const begin(), normal
template <typename Type>
constexpr typename vector<Type>::iterator vector<Type>::begin() noexcept
{
    return vector_iterator<Type>(ptr_data_);
}

// const begin(), causes "C2373: redefinition; different type modifiers"
template <typename Type>
constexpr typename vector<Type>::const_iterator vector<Type>::begin() const noexcept
{
    return const_iterator(ptr_data_);
}

// cbegin(), causes "C2373: redefinition; different type modifiers"
template <typename Type>
constexpr typename vector<Type>::const_iterator vector<Type>::cbegin() const noexcept
{
    return const_iterator(ptr_data_);
}

// non-const end(), normal
template <typename Type>
constexpr typename vector<Type>::iterator vector<Type>::end() noexcept
{
    return iterator(ptr_data_ + size_);
}

// const end(), causes "C2373: redefinition; different type modifiers"
template <typename Type>
constexpr typename vector<Type>::const_iterator vector<Type>::end() const noexcept
{
    return const_iterator(ptr_data_ + size_);
}

// cend(), causes "C2373: redefinition; different type modifiers"
template <typename Type>
constexpr typename vector<Type>::const_iterator vector<Type>::cend() const noexcept
{
    return const_iterator(ptr_data_ + size_);
}

// simplified vector_iterator
template <typename Type>
class vector_iterator
{
public:
    explicit vector_iterator(Type* ptr) : iterator_ptr_(ptr) {}; // iterator constructor

private:
    Type* iterator_ptr_ = nullptr;
};

int main(void)
{
    vector<int> tmp; // tries to construct a vector
    return 0;
}

Visual Studio produce an error list as follows:

Code Description Line (marked in the comments)
C2373 'clb_container::vector<Type,Allocator>::begin': redefinition; different type modifiers 43
C2373 'clb_container::vector<Type,Allocator>::cbegin': redefinition; different type modifiers 50
C2373 'clb_container::vector<Type,Allocator>::end': redefinition; different type modifiers 64
C2373 'clb_container::vector<Type,Allocator>::cend': redefinition; different type modifiers 71

The debug log is as follows:

Build started at 21:51...
1>------ Build started: Project: Development Test, Configuration: Debug x64 ------
1>Development Test.cpp
1>Development Test.cpp(43,63): error C2373: 'vector<Type>::begin': redefinition; different type modifiers
1>Development Test.cpp(21,43):
1>see declaration of 'vector<Type>::begin'
1>Development Test.cpp(50,63): error C2373: 'vector<Type>::cbegin': redefinition; different type modifiers
1>Development Test.cpp(22,43):
1>see declaration of 'vector<Type>::cbegin'
1>Development Test.cpp(64,63): error C2373: 'vector<Type>::end': redefinition; different type modifiers
1>Development Test.cpp(25,43):
1>see declaration of 'vector<Type>::end'
1>Development Test.cpp(71,63): error C2373: 'vector<Type>::cend': redefinition; different type modifiers
1>Development Test.cpp(26,43):
1>see declaration of 'vector<Type>::cend'
1>Done building project "Development Test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 21:51 and took 00.648 seconds ==========

I have tried the following steps:

  • I commented all the methods mentioned above and recompiled it. Errors disappeared at once.
  • Then I uncommented them one by one and found that whenever one of const version of begin(), const version of end, cbegin() and cend() is available, C2373 would occurred again.
  • I passed each of these code snippets to Copilot and Claude-3-Sonnet, respectively, and they found no obvious redefinitions.
  • At last, I installed "C++ Clang tools for Windows under Desktop development with C++" with Visual Studio Installer, and configured the test project to use Clang. C2373 disappeared, and the program compiled normally. However, if I changed the "Platform Toolset" back to the default "Visual Studio 2022(v143)", errors occur again. So I think this problem is probably caused by Visual C++ 2022.

However, as a part of my tiny STL, I hope it can compile normally under most compilers, rather than failing for some inexplicable reason, especially on a platform with many users like Visual Studio, but I still can't find the real problem.

1

There are 1 best solutions below

1
Christian Stieber On

constexpr implies const...

 constexpr iterator begin() noexcept;
 constexpr const_iterator begin() const noexcept;

are the same thing, except for return type. And you can't do overloads that only differ in return type.

Still; I'm confused as to why it compiles with some compilers... so I might actually be horribly wrong...

Ok, cppreference says:

A constexpr specifier used in an object declaration or non-static member function(until C++14) implies const

Are we looking at different language standards on the compilers that you tried?