Register    Login    Forum    Search    FAQ

Board index » Everything




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post Posted: December 19th, 2017, 10:06 am 
 

Joined: February 28th, 2013, 3:23 am
Posts: 2970
Location: Oklahoma, United States
It sure is nice to have all these great features allowing a programmer to be so lazy. So, normally, I put stuff like DotProduct, Normalize, Length and LengthSq in the vector classes that they need to work on, but lately, I've been messing around with templates and some C++17 features as Visual Studio allows. One of them is if constexpr. What this does is allows you to, in a function, determine which code path to COMPILE not just run as long as the condition is a constexpr value.

Here is my DotProduct example
Code:
// Only dealing with float base types; _Vec2<float>, _Vec3<float>

// Just to make code look nicer in function
template<class VecType>
constexpr void VecType_Error()
{
   static_assert( !(is_vec2 && is_vec3), "Requires VecType to be a _Vec2<float or _Vec3<float>." );
}

template<class VecType>
float operator*( const VecType& lhs, const VecType& rhs )
{
   return DotProduct( lhs, rhs );
}

template<class VecType>
float DotProduct( const VecType& lhs, const VecType& rhs )
{
   // absurd value indicating you passed in something you shouldn't have
   float result = std::limits<float>::max();

   constexpr auto is_vec2 = std::is_same_v<VecType, Vec2>;
   constexpr auto is_vec3 = std::is_same_v<VecType, Vec3>;

   // Test for Vec2
   if constexpr( is_vec2 )
   {
      result = lhs.x * rhs.x + lhs.y * rhs.y;
   }
   else if constexpr( is_vec3 )
   {
      result = lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
   }
   else
   {
      // Will show error message in Output window if path is compiled
      VecType_Error<VecType>();
   }
   
   return result;
}


Now I can write two function instead of 6. Granted, this could be done without the if constexpr, but you would pay a runtime branching penalty. This way, it's decided at compile time which branch to take.

_________________
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com


Top 
 Profile  
Reply with quote  
 Post Posted: December 19th, 2017, 10:28 am 
 

Joined: February 28th, 2013, 3:23 am
Posts: 2970
Location: Oklahoma, United States
Not sure about CrossProduct though. The Vec2 type returns a float, and the Vec3 type returns a Vec3.

Code:
template<class VecType>
auto operator%( const VecType& lhs, const VecType& rhs )->decltype( CrossProduct( lhs, rhs )
{
   VecType_Error<VecType>();
   return CrossProduct( lhs, rhs );
}

float CrossProduct( const Vec2& lhs, const Vec2& rhs )
{
   return (lhs.y * rhs.x) - (lhs.x * rhs.y);
}
Vec3 CrossProduct( const Vec3& lhs, const Vec3& rhs )
{
   return {
   (lhs.y * rhs.z) - (lhs.z * rhs.y),
   (lhs.z * rhs.x) - (lhs.x * rhs.z),
   (lhs.x * rhs.y) - (lhs.y * rhs.x)
   };
}


I wouldn't know how to get the CrossProduct functions to auto deduce their return type since not only are the return types different, but also they way they are calculated. If not possible, then I only saved one function.

_________________
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com


Top 
 Profile  
Reply with quote  
 Post Posted: December 19th, 2017, 11:08 am 
 

Joined: February 28th, 2013, 3:23 am
Posts: 2970
Location: Oklahoma, United States
Ok, I think I have a way. I just put a public type alias inside those vector classes and use that as the return type.

Code:
template<class T>
class _Vec2
{
public:
   using CrossReturnType = T;
};

template<class T>
class _Vec3
{
public:
   using CrossReturnType = _Vec3<T>;
};

template<class VecType>
auto operator*( const VecType& lhs, const VecType& rhs )->typename VecType::CrossReturnType
{
   return CrossProduct( lhs, rhs );
}

template<class VecType>
auto CrossProduct( const VecType& lhs, const VecType& rhs )->typename VecType::CrossReturnType
{
   constexpr auto is_vec2 = std::is_same_v<VecType, _Vec2<float>>;
   constexpr auto is_vec3 = std::is_same_v<VecType, _Vec3<float>>;
   static_assert( is_vec2 || is_vec3, "Not a valid vector or not implemented." );

   if constexpr( is_vec2 )
   {
      // return Vec2 cross
   }
   else
   {
      // return Vec3 cross
   }
}


Haven't tried this yet, still working on some things.

_________________
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com


Top 
 Profile  
Reply with quote  
 Post Posted: December 20th, 2017, 3:25 am 
Site Admin
User avatar

Joined: December 31st, 2011, 4:53 pm
Posts: 3538
Location: Japan
consexpr if can do some cool shit.

It is not true that without constexpr if you will pay a runtime branching penalty. The compiler will remove the branch for a if( true ) or if( false). Also, for branches where the same path is taken every time, but overhead is negligible since the branch predictor will never fail (or will only fail the first time). There are some exceptions to this rule (which can also often be dealt with with PGO), but in general that is the gist.

The real place that constexpr if shines is when you need to write templated code that will not be guaranteed to be well-formed depending on the template param. In that case, with a normal if it will be compiled, and the compilation will fail (or at least, the template overload will be removed from the candidate list via SFINAE). But with constexpr if, you can have code in the function that is ill formed, and it will not be touched by the compiler if the predicate evaluates to false.

_________________
Chili


Top 
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
 
Post new topic Reply to topic  [ 4 posts ] 

Board index » Everything


 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
cron