Разное поведение type traits в конструкторе и методах класса

Вот мой класс в котором конструкторы вызывают методы в качестве инициализатора. Сигнатуры конструкторов и этих методов идентичны (с той лишь разницей, что одни - конструкторы, а другие - методы, которые что-то возвращают)

#include <iostream>
#include <vector>
#include <type_traits>
#include <concepts>

// TMyClass ********************************************************************************
template <size_t Size>
class TMyClass {
public:

    using TData = std::vector<size_t>;

private:

    TData data;

protected:

    template <std::integral size_type>
    TData InitData(const size_type(&arr)[Size]) {
        std::vector<size_t> tmp(Size);
        for (size_t i = 0; i < Size; ++i) {
            tmp[i] = arr[i];
        }
        return tmp;
    }

    template <std::integral size_type>
    TData InitData(const size_type* arr, size_t size = Size) {
            if (size != Size) throw;
        std::vector<size_t> tmp(Size);
        for (size_t i = 0; i < Size; ++i) {
            tmp[i] = arr[i];
        }
        return tmp;
    }

public:

    template <std::integral size_type>
    TMyClass(const size_type(&arr)[Size])
        : data(InitData(arr)) // <------------------ ERROR
    {}

    template <std::integral size_type>
    TMyClass(const size_type* arr, size_t size = Size)
        : data(InitData(arr, size))
    {}

};

// M A I N ********************************************************************************
int main()
{
    int arr[3] = { 3, 4, 5 };
    TMyClass<3> obj1(arr);

    std::vector<int> vec = { 1, 2, 3 };
    TMyClass<3> obj2(vec.data()); // <------------------ ?????


    std::cout << "\n\n  - the end -\n";
    std::cout << "press [Enter]...";
    std::cin.get();
}

В итоге я получаю ошибку (строка в коде помечена "<------------------ ERROR"):

TMyClass<3>::InitData: неоднозначный вызов перегруженной функции

Казалось бы всё логично и исправление на

template <std::integral size_type>
TData InitData(const size_type* arr, size_t size) {
// ...
}

(убираем значение по умолчанию для аргумента size) решает вопрос.

НО! Почему тогда эта ошибка не возникает на строке

TMyClass<3> obj2(vec.data()); // <------------------ ?????

Ведь в конструкторе

template <std::integral size_type>
TMyClass(const size_type* arr, size_t size = Size)
    : data(InitData(arr, size))
{}

это значение по умолчанию для аргумента size всё еще есть.

PS: Вопрос не в логике класса: Как правильно/не правильно? Вопрос в том, почему разное поведение в одинаковых (как мне кажется) ситуациях?

PPS: Использование стандартных type_traits

template <typename size_type, std::enable_if_t< std::is_integral_v<size_type>, bool > = true>

даёт тот же результат

PPS: Тестировал на Visual Studio и Qt


Ответы (2 шт):

Автор решения: isnullxbh

НО! Почему тогда эта ошибка не возникает на строке

Потому что существует неявное преобразование array-to-pointer, но не наоборот :)

int arr[3];
int (&r1)[3] = arr; // Ok
int*  r2     = arr; // Ok

int* ptr;
int (&r3)[3] = ptr; // Ошибка
int*  r4     = ptr; // Ок
→ Ссылка
Автор решения: sibedir

Вроде разобрался благодаря @Harry и @isnullxbh. Действительно, моё предположение:

Вопрос в том, почему разное поведение в одинаковых (как мне кажется) ситуациях?

было не верным. Я не внимательно отнёсся к приведению типов.

Код, поведение которого соответствует тому, что я от него ожидал:

#include <iostream>
#include <vector>
#include <concepts>

template <typename T>
concept integral_pointer = std::is_pointer_v<T> && std::integral<typename std::remove_pointer<T>::type>;

// TMyClass ********************************************************************************
template <size_t Size>
class TMyClass {
public:

    using TData = std::vector<size_t>;

private:

    TData data;

protected:

    template <std::integral size_type>
    TData InitData(const size_type(&arr)[Size]) {
        TData tmp(Size);
        for (size_t i = 0; i < Size; ++i) {
            tmp[i] = arr[i];
        }
        return tmp;
    }

    template <integral_pointer size_type_ptr>
    TData InitData(size_type_ptr arr, size_t size = Size) {
        if (size != Size) throw;
        TData tmp(Size);
        for (size_t i = 0; i < Size; ++i) {
            tmp[i] = arr[i];
        }
        return tmp;
    }

public:

    template <std::integral size_type>
    TMyClass(const size_type(&arr)[Size])
        : data(InitData(arr))
    {}
    
    template <integral_pointer size_type_ptr>
    TMyClass(size_type_ptr arr, size_t size = Size)
        : data(InitData(arr, size))
    {}

};

// M A I N ********************************************************************************
int main()
{
    int arr[3] = { 3, 4, 5 };
    TMyClass<3> obj0(arr);

    const int (&ref_arr)[3] = arr;
    TMyClass<3> obj1(ref_arr);

    int* const ptr = new int[3]{ 1, 2, 3 };
    TMyClass<3> obj2(ptr);

    int const* const& ref_ptr = ptr;
    TMyClass<3> obj3(ref_ptr);

    delete[] ptr;

    std::cout << "\n\n  - the end -\n";
    std::cout << "press [Enter]...";
    std::cin.get();
}
→ Ссылка