Search code examples
c++templatestemplate-specializationincomplete-type

Special rules regarding SFINAE for incomplete types


Recently while answering a question here if-else depends on whether T is a complete type I realized that the following does not compile

#include <iostream>
#include <type_traits>

using namespace std;

class Incomplete;
class Complete {};

template <typename IncompleteType>
struct DetermineCompleteHelper : public IncompleteType {};

template <typename IncompleteType, typename = std::enable_if_t<true>>
struct DetermineComplete {
    static constexpr const bool value = false;
};

template <typename IncompleteType>
struct DetermineComplete<IncompleteType, std::enable_if_t<std::is_same<
        decltype(DetermineCompleteHelper<IncompleteType>{}),
        decltype(DetermineCompleteHelper<IncompleteType>{})>::value>> {
    static constexpr const bool value = true;
};

int main() {
    cout << DetermineComplete<Complete>::value << endl;
    cout << DetermineComplete<Incomplete>::value << endl;
    return 0;
}

But changing the partial template specialization to

template <typename IncompleteType>
struct DetermineComplete<IncompleteType, std::enable_if_t<std::is_same<
        std::integer_sequence<int, sizeof(IncompleteType)>,
        std::integer_sequence<int, sizeof(IncompleteType)>>::value>> {
    static constexpr const bool value = true;
};

makes the code compile without errors, why this irregularity? Shouldn't the first expression be treated as an error within the context of the partial specialization and thus have SFINAE kick in and make the default definition of the class the one that is instantiated?


Solution

  • The error occurs when attempting to instantiate the definition of DetermineCompleteHelper<IncompleteType> (in particular, it attempts to derive from a base class that is incomplete). That's outside the immediate context.