Is there a way to force a function to return a type name?

I recently worked on a project and wanted to give preference to certain types when performing operations other than standard. To do this, I tried to use a template in some way to determine what data types are used. The code I wrote clearly does not work, but it gets an idea of ​​what I'm trying to do through

#include <iostream> template <type1,type2> typename determine(type1 a, type2 b) { if (typeid(type1) == typeid(int) || typeid(type2) == typeid(int)) return int; else return double; } int main() { int a = 3; double b = 2; std::cout << (static_cast<determine(a, b)>(a) / static_cast<determine(a, b)>(b)) << std::endl; } 

Is there a way to determine what returns something that I can use to decide which data type to use?

+6
source share
3 answers

You can use template metaprogramming methods to achieve your goal.

 template <typename T1, typename T2> struct TypeSelector { using type = double; }; template <typename T1> struct TypeSelector<T1, int> { using type = int; }; template <typename T2> struct TypeSelector<int, T2> { using type = int; }; template <> struct TypeSelector<int, int> { using type = int; }; 

and then use:

 int main() { int a = 3, b = 2; using type1 = TypeSelector<decltype(a), decltype(b)>::type; std::cout << (static_cast<type1>(a) / static_cast<type1>(b)) << std::endl; float c = 4.5f; using type2 = TypeSelector<decltype(a), decltype(c)>::type; std::cout << (static_cast<type2>(a) / static_cast<type2>(c)) << std::endl; using type3 = TypeSelector<decltype(c), decltype(a)>::type; std::cout << (static_cast<type3>(c) / static_cast<type3>(a)) << std::endl; } 
+5
source

I am sure you can do this with std::conditional and several std::is_same logically concatenated through || :

 #include <iostream> #include <type_traits> template<class T1, class T2> using determine = typename std::conditional< std::is_same<T1,int>::value || std::is_same<T2,int>::value, int, double>::type; int main() { int a = 3; double b = 2; long c = 3L; using type1 = determine<decltype(a),decltype(b)>; std::cout << (static_cast<type1>(a) / static_cast<type1>(b)) << std::endl; using type2 = determine<decltype(b),decltype(c)>; std::cout << (static_cast<type2>(b) / static_cast<type2>(c)) << std::endl; } 
+6
source

Here is another working solution that you can use for this.
The basic idea is to rely on function overloading and sfinae to send a request and avoid multiple definitions.
This follows a minimal working example:

 #include<type_traits> #include<utility> #include<cassert> template <typename T1, typename T2> typename std::enable_if<std::is_same<T1, int>::value or std::is_same<T2, int>::value, int>::type determineImpl(int, T1 a, T2 b) { return 42; } template <typename T1, typename T2> typename std::enable_if<not std::is_same<T1, int>::value and not std::is_same<T2, int>::value, double>::type determineImpl(char, T1 a, T2 b) { return .42; } template<typename... Args> auto determine(Args&&... args) -> decltype(determineImpl(0, std::forward<Args>(args)...)) { return determineImpl(0, std::forward<Args>(args)...); } int main() { auto v1 = determine(42, 'c'); assert(v1 == 42); auto v2 = determine('c', .42); assert(v2 == .42); } 
0
source

All Articles