During the implementation of a class that has SFINAE based ctor, I get the next error: In template: no type named 'type' in 'std::enable_if<false, void *>'; 'enable_if' cannot be used to disable this declaration
The SFINAE is based on previous template which is been worked on before.
The code is:
#include <iostream>
#include <type_traits>
namespace infra {
namespace io {
struct IoDataFrameFactory {};
struct IoDataFrame {};
}
}
template<typename T1, typename T2>
class IoDataFramePair : public infra::io::IoDataFrame {
public:
IoDataFramePair(std::istream &is, const infra::io::IoDataFrameFactory &factory,
typename std::enable_if_t<(std::is_constructible_v<T1, std::istream &, const infra::io::IoDataFrameFactory &> &&
std::is_constructible_v<T2, std::istream &, const infra::io::IoDataFrameFactory &>), void *> = nullptr)
: first(is, factory), second(is, factory)
{
checkSuffix(is);
}
IoDataFramePair(std::istream &is, const infra::io::IoDataFrameFactory &factory,
typename std::enable_if_t<(!std::is_constructible_v<T1, std::istream &, const infra::io::IoDataFrameFactory &>
&&
std::is_constructible_v<T2, std::istream &, const infra::io::IoDataFrameFactory &>), void *> = nullptr)
: first(is), second(is, factory)
{
checkSuffix(is);
}
IoDataFramePair(std::istream &is, const infra::io::IoDataFrameFactory &factory,
typename std::enable_if_t<(std::is_constructible_v<T1, std::istream &, const infra::io::IoDataFrameFactory &> &&
!std::is_constructible_v<T2, std::istream &, const infra::io::IoDataFrameFactory &>), void *> = nullptr)
: first(is, factory), second(is)
{
checkSuffix(is);
}
IoDataFramePair(std::istream &is, const infra::io::IoDataFrameFactory &factory,
typename std::enable_if_t<(!std::is_constructible_v<T1, std::istream &, const infra::io::IoDataFrameFactory &>
&&
!std::is_constructible_v<T2, std::istream &, const infra::io::IoDataFrameFactory &>), void *> = nullptr)
: first(is), second(is)
{
checkSuffix(is);
}
private:
int m_version;
// Define other members and functions as needed
void checkSuffix(std::istream &is)
{
// Implement checkSuffix logic
}
std::istream m_beginIS;
std::istream m_middleIs;
T1 first;
T2 second;
};
int main()
{
// Usage example
std::stringstream is(); // You need to provide an actual input stream
infra::io::IoDataFrameFactory factory; // You need to provide an actual IoDataFrameFactory
IoDataFramePair<int, double> pair1(is, factory); // Calls the appropriate constructor
IoDataFramePair<int, int> pair2(is, factory); // Calls the appropriate constructor
// Similar usage for other cases
return 0;
}
What am I doing wrong and how to fix it?
You need to make the types you test dependent types. Here are two ways adding U1
and U2
that defaults to T1
and T2
.
template <class U1 = T1, class U2 = T2, std::enable_if_t<
(std::is_constructible_v<U1, std::istream&,
const infra::io::IoDataFrameFactory&> &&
std::is_constructible_v<U2, std::istream&,
const infra::io::IoDataFrameFactory&>)>* =
nullptr>
IoDataFramePair(std::istream& is, const infra::io::IoDataFrameFactory& factory)
: first(is, factory), second(is, factory) {
checkSuffix(is);
}
template<class U1 = T1, class U2 = T2>
IoDataFramePair(
std::istream& is, const infra::io::IoDataFrameFactory& factory,
std::enable_if_t<
(!std::is_constructible_v<U1, std::istream&,
const infra::io::IoDataFrameFactory&> &&
std::is_constructible_v<U2, std::istream&,
const infra::io::IoDataFrameFactory&>)>* =
nullptr)
: first(is), second(is, factory) {
checkSuffix(is);
}
... and do the same for the other two constructors.
Demo - Note: I prefer to keep the extra argument out of the constructors (version 1 above) so I used that approach in all constructors in the demo.
Note: You have other problems, like trying to default construct istream
s and trying to initialize and int
and a double
with an istream
, but I think that's beside the point.