This question combines several pieces of code and is a bit complicated, but I tried slimming it down as much as possible.
I am trying to use std::enable_if
to conditionally invoke the correct constructor as a result of ambiguous function signatures when a lambda expression is used as input, but the parameters of said lambda expression can be implicitly convertible to one another.
This is an attempt to build upon the following question: Here, but is sufficiently different and focuses on std::enable_if
to merit another question. I am also providing the Live Example that works with the problem parts commented out.
To inspect the argument (and result) types of the functor, I have the following class:
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
enum { num_args = sizeof...(Args) };
typedef ReturnType result_type;
template <size_t N>
struct arg
{
typedef typename std::tuple_element<N, std::tuple<Args...>>::type type;
// the i-th argument is equivalent to the i-th tuple element of a tuple
// composed of those arguments.
};
};
Then I try to run the below code, however, the std::enable_if
part does not seem to work, but I know that everything within the brackets does (or should) work as demonstrated by the Live Example.
template<typename data_type, typename Type1, typename Type2>
class A
{
public:
using a_type = std::tuple<Type1, Type2>;
using b_type = std::tuple<std::size_t,std::size_t>;
template<typename Lambda, typename = std::enable_if_t<std::is_same<typename function_traits<Lambda>::arg<0>::type, b_type>::value>>
A(const Lambda& Initializer)
{
std::cout << "idx_type" << std::endl;
}
template<typename Lambda, typename = std::enable_if_t<std::is_same<typename function_traits<Lambda>::arg<0>::type, a_type>::value>>
A(const Lambda& Initializer)
{
std::cout << "point_type" << std::endl;
}
};
int main()
{
auto f = [](std::tuple<long long, int>) -> double { return 2; };
std::cout << std::is_same<typename function_traits<decltype(f)>::arg<0>::type, std::tuple<std::size_t, std::size_t>>::value
<< std::is_same<typename function_traits<decltype(f)>::arg<0>::type, std::tuple<long long, int>>::value;
auto a = A<double, long long, int>{
[](std::tuple<long long, int>) -> double { return 1; }
};
auto b = A<double, long long, int>{
[](std::tuple<std::size_t, std::size_t>) -> double { return 2; }
};
}
So what am I missing? I am working off example #5 here.
std
namespace? Besides a very few exceptions, doing that is explicitly undefined behavior. – Lendtypename = std::enable_if_t<cond>
should bestd::enable_if_t<cond, bool> = false
. – Mafiastd
fromfunction_traits
and also I triedstd::enable_if_t<cond, bool> = false
but it doesn't work. @Jarod42, what do you mean? – Carbamatetemplate
for dependent name. – Cauley