I have checked out std::enable_if to conditionally compile a member function
However it doesn't work for me. I need to restrict T
of a class method to some types.
template<typename T = typename enable_if_t<
is_same_v<T, long> || is_same_v<T, int> || is_same_v<T, double>
|| is_same_v<T, float> || is_same_v<T, size_t>>
>
shared_ptr<Node<T>> LinkedList<T>::AddNumbers(
shared_ptr<Node<T>> p1, shared_ptr<Node<T>> p2, T carry)
{
<snip>
}
I get build error:
identifier T is undefined
I am using C 20. Any advice and insight is appreciated.
I try out concepts
suggested by @JeJo, but get the following build error on the line performing arithmetics:
error C2676: binary '/': 'T' does not define this operator or
a conversion to a type acceptable to the predefined operator
I have the template class declaration in header file and implementation in .cpp
file. Header file:
template <typename T> class LinkedList
{
public:
<snip>
shared_ptr<Node<T>> AddNumbers(
shared_ptr<Node<T>>, shared_ptr<Node<T>>, T carry = 0);
};
When I use the suggestion by @JeJo, I bump into
error C3855: 'LinkedList<T>': template parameter 'T' is
incompatible with the declaration
CodePudding user response:
Since you are using c 20, you can use concept to solve this.
// define concept: you can use it other conditionally enabling members
template<typename T>
concept ValidType = std::is_same_v<T, long> || std::is_same_v<T, int>
|| std::is_same_v<T, size_t>
|| std::is_floating_point_v<T> /* so on ... */;
template <typename T> class LinkedList
{
public:
template<ValidType Type> // declaration must be templated for SFINAE
std::shared_ptr<Node<Type>> AddNumbers(std::shared_ptr<Node<Type>>
, std::shared_ptr<Node<Type>>, Type carry = 0);
};
// definition: if you insist to put outside of the class
template<typename T>
template<ValidType Type>
std::shared_ptr<Node<Type>> LinkedList<T>::AddNumbers(std::shared_ptr<Node<Type>>
, std::shared_ptr<Node<Type>>, Type carry)
{
return {};
}
If you insist, doing it with std::enable_if
, you can do it with trailing return, something like:
// variable template boolean for type check;
// can be used in other conditionally enabling members
template<typename T>
inline constexpr bool is_vaild_type = std::is_same_v<T, long> || std::is_same_v<T, int>
|| std::is_same_v<T, size_t>
|| std::is_floating_point_v<T> /*|| so on ... */;
template<typename T>
auto LinkedList<T>::AddNumbers(shared_ptr<Node<T>> p1, std::shared_ptr<Node<T>> p2, T carry)
-> std::enable_if_t<is_vaild_type<T>, std::shared_ptr<Node<T>>
{
// ...
}
Note that I have used std::is_floating_point_v
instead of checking the types float
and double
.
CodePudding user response:
Use C 20 concepts
#include <memory>
#include <concepts>
template<typename T>
class LinkedList {
public:
template<typename U = T>
requires std::same_as<U, long>
|| std::same_as<U, int>
|| std::same_as<U, size_t>
|| std::same_as<U, double>
|| std::same_as<U, float>
std::shared_ptr<Node<U>>
AddNumbers(std::shared_ptr<Node<U>>, std::shared_ptr<Node<U>>, U carry = 0);
};
CodePudding user response:
Despite what the other answers say, the member function doesn't need to (and shouldn't) be a template, assuming you use requires
. That's only necessary when you use the classical SFINAE.
#include <cstddef>
#include <iostream>
#include <memory>
#include <type_traits>
template <typename T, typename ...P>
concept one_of = (std::is_same_v<T, P> || ...);
template <typename T>
struct Node {};
template <typename T>
class LinkedList
{
public:
std::shared_ptr<Node<T>> AddNumbers(std::shared_ptr<Node<T>>, std::shared_ptr<Node<T>>, T carry = 0)
requires one_of<T, int, long, std::size_t, float, double>
{
// ...
}
};
int main()
{
LinkedList<int> s;
s.AddNumbers(nullptr, nullptr, 0);
LinkedList<char> t;
// t.AddNumbers(nullptr, nullptr, 0);
}
Any boolean condition can be spelled after requires
, but I've added a concept for brevity.