Reputation: 32192
I was reading somewhere that it would be possible to do c++ metaprogramming using function overloads instead of SFINAE. I came up with a toy exercise to test this. I want to detect if a particular type is a nested vector. My code that works is
#include <type_traits>
#include <vector>
#include <iostream>
template <typename T> struct Tag {};
template <typename TLeaf >
consteval bool is_nested(Tag<TLeaf>)
{
return true;
}
template <typename TLeaf , typename TSub, typename enable = std::enable_if_t< !std::is_same_v<TLeaf, TSub> >>
consteval bool is_nested(Tag<TSub>)
{
return false;
}
template <typename TLeaf , typename TSub>
consteval bool is_nested(Tag<std::vector<TSub>>)
{
return is_nested<TLeaf>(Tag<TSub>{});
}
template <typename TSub, typename TLeaf>
consteval bool is_nested()
{
return is_nested<TLeaf>(Tag<TSub>{});
}
int main(){
using type_nested1 = std::vector<std::string>;
using type_nested2 = std::vector<type_nested1>;
std::cout << is_nested<type_nested1, std::string>() << std::endl;
std::cout << is_nested<type_nested2, std::string>() << std::endl;
std::cout << is_nested<int, std::string>() << std::endl;
std::cout << is_nested<type_nested1, int>() << std::endl;
std::cout << is_nested<type_nested2, int>() << std::endl;
}
https://godbolt.org/z/zGEf9cej5
and the output is
Program returned: 0
Program stdout
1
1
0
0
0
but I'm disappointed that I had to use std::enable_if_t
to disambiguate the two overloads. Can this be rewritten to keep the spirit of the exercise but eliminate any SFINAE crud from the solution?
Upvotes: 0
Views: 100
Reputation: 303387
If you just pass two arguments all the way through, you don't need to do anything special:
template <typename T> struct Tag {};
template <typename T> inline constexpr Tag<T> tag;
template <typename T>
consteval bool is_nested(Tag<T>, Tag<T>) {
return true;
}
template <typename L, typename T>
consteval bool is_nested(Tag<L>, Tag<T>) {
return false;
}
template <typename L, typename T>
consteval bool is_nested(Tag<std::vector<L>>, Tag<T>) {
return is_nested(tag<L>, tag<T>);
}
template <typename L, typename T>
consteval bool is_nested() {
return is_nested(tag<L>, tag<T>);
}
Where you can combine the first two overloads into one:
template <typename L, typename T>
consteval bool is_nested(Tag<L>, Tag<T>) {
return std::is_same_v<L, T>;
}
Which was also true of your original example (but it's easier to see if all your parameters are in the same spot):
template <typename TLeaf , typename TSub>
consteval bool is_nested(Tag<TSub>) {
return std::is_same_v<TLeaf, TSub>;
}
Upvotes: 2