Type condition in template
Since C++17 there is a way to do exactly this with if-constexpr. The following compiles since clang-3.9.1, gcc-7.1.0, and recent MSVC compiler 19.11.25506 handles well too with an option /std:c++17.
#include <iostream>
#include <type_traits>
template<typename T>
void printType(T)
{
if constexpr (std::is_same_v<T, const char*>)
std::cout << "const char*" << std::endl;
else if constexpr (std::is_same_v<T, int>)
std::cout << "int" << std::endl;
else
std::cout << "???" << std::endl;
}
int main()
{
printType("Hello world!");
printType(1);
printType(1.1);
return 0;
}
Output:
const char*
int
???
Template class with conditional typenames
Typically you'd do this by creating a trait type whose specializations define the additional types. For example:
// Base template is undefined.
template <typename T>
struct optix_traits;
template <>
struct optix_traits<float> {
using dim2 = optix::float2;
// etc
};
template <>
struct optix_traits<double> {
using dim2 = optix::double2;
// etc
};
Then you can alias from these types to a name in your type, if desired:
template <typename T>
class MyClass {
public:
using T2 = typename optix_traits<T>::dim2;
};
C++ template with condition for type
You are most of the way there already. In order to overload SFINAE, you need to use a non-type template parameter with an assigned default value instead of using defaulted type template parameter.
So, we change both functions to use a non-type paramere with a default value, and just negate the condition like:
template<typename ValueType>
class Comparator {
public:
...
template<
typename T = ValueType,
std::enable_if_t<
!std::is_floating_point<std::remove_reference_t<ValueType>>::value,
// ^- not here, so only non-floating point types allowed
bool> = true // set the bool to true, this lets us call the function without providing a value for it
>
bool passed(T actualValue) { non floating point code here }
template<
typename T = ValueType,
std::enable_if_t<
std::is_floating_point<std::remove_reference_t<T>>::value,
bool> = true // set the bool to true, this lets us call the function without providing a value for it
>
bool passed(T actualValue, T eps) { floating point code here }
Type condition in C++ template class problem
In the second case, what RET
is, depends on the template type T
. The compiler needs to be assured that it is going to be a type in all possible instantiations (and not perhaps a static member of some instantiation of IF). You do so with the typename
keyword.
template <typename T>
class Param
{
typename IF< sizeof(int)<sizeof(long), T&, T* >::RET mParam;
};
template class default type and condition
You can add static_assert
to perform the checking.
template <typename T=std::conditional_t<sizeof(void*) == 8, std::uint64_t, std::uint32_t>>
class MyClass
{
static_assert(std::is_same_v<T, std::uint64_t> || std::is_same_v<T, std::uint32_t>, "T must be std::uint64_t or std::uint32_t");
private:
std::vector<T> vs;
public:
// ...
};
LIVE
condition in template function implementation depending on whether the type is a pointer
Tag dispatch:
template< typename T >
void AbstractEvent::setVar_impl( QString varName, T value, std::true_type /*is_ptr*/)
{
void * castValue = static_cast<void*>(value);
if (castValue)
{
//do sth with castValue
}
}
template< typename T >
void AbstractEvent::setVar_impl( QString varName, T value, std::false_type /*is_ptr*/)
{
//do something with value
}
template< typename T >
void AbstractEvent::setVar( QString varName, T value){
setVar_impl(varName, value, std::is_pointer<T>());
}
Alternatively, overload and then SFINAE out the inapplicable one:
template<typename T>
typename std::enable_if<std::is_pointer<T>::value>::type
AbstractEvent::setVar(QString varName, T value)
{
void * castValue = static_cast<void*>(value);
if (castValue)
{
//do sth with castValue
}
}
template< typename T>
typename std::enable_if<!std::is_pointer<T>::value>::type
AbstractEvent::setVar( QString varName, T value)
{
//do something with value
}
Third alternative, overload directly:
template< typename T >
void AbstractEvent::setVar( QString varName, T* value)
{
void * castValue = static_cast<void*>(value);
if (castValue)
{
//do sth with castValue
}
}
template< typename T >
void AbstractEvent::setVar( QString varName, T value)
{
//do something with value
}
The first template is more specialized than the second by partial ordering, so will be chosen if both are equally viable.
You may also want to special case the T == nullptr_t
case. nullptr_t
isn't a pointer type, but you probably want the pointer overload to be called in that situation.
Type depends on condition in template
You only have to add a ::type
and a typename
template <bool two>
// ......*typename*.....................................................*::type*
void foo (typename std::conditional<two, double*, std::complex<double>* >::type input, size_t n)
{
for (size_t i = 0; i < n; ++n)
input[i] *= two ? 2.0 : 1.0;
}
Template overload based on condition
What I want to do is
template<typename Rect, typename Size /*if Size::width, use this*/>
Rect& move(Rect& rc, Size size);
template<typename Rect, typename Point /*if Point::x, use this*/>
Rect& move(Rect& rc, Point to);
I.e. choosing an overload depends on whether a template argument has a particular member. Is it possible in c++?
If you can use at least C++11... have you tried with SFINAE through trailing return type and decltype()
?
I mean... something as
template <typename Rect, typename Size>
auto move (Rect & rc, Size size)
-> decltype( size.width, rc );
// .............^^^^^^^^^^^ <-- note this
template <typename Rect, typename Point>
auto move(Rect& rc, Point to)
-> decltype( to.x, rc );
// .............^^^^^ <-- and note this
Obviously this doesn't works if you call move()
with a second argument with both a with
and a x
member: the compiler doesn't know which one move()
select.
How it works?
It's simple: the main word is SFINAE, that mean Substitution Failure Is Not An Error.
Take in count that decltype()
return the type of the contained expression, so (for example) from
decltype( size.width, rc );
the comma operator discard size.width
, if available (this is the important point!), and remain rc
, so decltype()
return the type of rc
(if size.width
exist!).
But what happens if size.width
doesn't exist?
You have a "substitution failure". That "is not an error" but remove this overloading version of move()
from the set of available move()
functions.
how to do an if else depending type of type in c++ template?
You could use typeid
:
if (typeid(T) == typeid(int))
Or you could use the std::is_same
type trait:
if (std::is_same<T, int>::value)
Related Topics
Reshaping a 1-D Array to a Multidimensional Array
Getter and Setter, Pointers or References, and Good Syntax to Use in C++
What Is Difference Between Const and Non Const Key
How to Determine Programmatically If an Expression Is Rvalue or Lvalue in C++
Copy Constructor in C++ Is Called When Object Is Returned from a Function
Google Protocol Buffers Compare
How Far to Go with a Strongly Typed Language
Is Shrink_To_Fit the Proper Way of Reducing the Capacity a 'Std::Vector' to Its Size
Automatically Generate C++ File from Header
Is It a Good Practice to Use Unions in C++
C++ Check If Statement Can Be Evaluated Constexpr
This Declaration Has No Storage Class or Type Specifier in C++
Why am I Not Provided with a Default Copy Constructor from a Volatile