SFINAE и неявное приведение при перегрузке функции - PullRequest
1 голос
/ 20 апреля 2020

Я пытаюсь написать шаблонный помощник, который позволяет мне проверять, соответствует ли набор типов типам членов структуры. Пока что я написал это -

#include <iostream>
#include <functional> 

struct foo {
    int field1;
    int field2;
};


template <typename...T, std::size_t ...indices >
constexpr bool construct (std::index_sequence<indices...>) {
    foo s = {std::get<indices>(std::tuple<T...>())...};
    return true;
}

template<typename...T>
static bool allowed(int) {
    construct<T...>(std::index_sequence_for<T...>());
    return true;
}

template<typename...T>
static bool allowed(long) {
    return false;
}

int main() {
    std::cout << allowed<int, int, int>(0); 
    return 0;
}

Здесь, очевидно, вызов allowed<int, int, int> недопустим, потому что конструкция не может быть вызвана (foo имеет 2 члена, и он инициализируется с 3). Но есть другая реализация allow, которая принимает long в качестве аргумента. Начиная с SFINAE, разве компилятор не должен просто соответствовать реализации второго шаблона allow и возвращать false? Но вместо этого он выдает ошибку -

ошибка: слишком много инициализаторов для 'foo'

foo s = {std::get<indices>(std::tuple<T...>())...};

Если я просто закомментирую Первая реализация разрешена, все слова в порядке, и я получаю ложное. Я запутался в том, как замена шаблона взаимодействует с неявными приведениями и перегрузкой функций. Если это не разрешено, есть ли способ добиться того же эффекта?

1 Ответ

2 голосов
/ 21 апреля 2020

foo находится вне непосредственного контекста, поэтому вы получаете серьезную ошибку вместо SFINAE. Учтите это:

#include <iostream>
#include <functional>

struct foo {
    int field1;
    int field2;
};

template <typename U, typename...T, std::size_t ...indices >
constexpr auto construct (std::index_sequence<indices...>) -> decltype(new U {std::get<indices>(std::tuple<T...>())...}) {
    return nullptr;
}

template<typename...T, typename Q = decltype(construct<foo, T...>(std::index_sequence_for<T...>()))>
static bool allowed(int) {
    return true;
}

template<typename...T>
static bool allowed(long) {
    return false;
}


int main() {
    std::cout << "allowed<int,int>(0) = " << allowed<int,int>(0) << std::endl;
    std::cout << "allowed<int,int,int>(0) = " << allowed<int,int,int>(0) << std::endl;
    return 0;
}
...