I have a function template from an external library that needs user-defined type for using it.
template < int runtime_t >
typename ExtLib::apply<runtime_t>::type get_value(std::string) ;
To use it, I need to specify the user-defined type like:
get_value<ExtLib::pool_t::boolean_>("key_of_boolean_value");
get_value<ExtLib::pool_t::float_>("key_of_float_value");
I would like to wrap this "ExtLib" in order to hide it from the main program in such way I can use it with builtin cpp type:
bool val = get_value<bool>("key");
float val2 = get_value<float>("key2");
I've tried using a map but without any success. Is it even possible?
You could make mapping from standard types to lib types via class templates:
template <typename T>
struct Convert;
template <>
struct Convert<bool>
{
static const int value = ExtLib::pool_t::boolean;
};
template <>
struct Convert<float>
{
static const int value = ExtLib::pool_t::float;
};
.. map other types
and then
template <typename T>
auto get_value(const std::string& key)
{
return get_value<Convert<T>::value>(key)
}
Or you could define a function template get_value in your own namespace, and overload or specialize it to use the function with the same name from the library namespace, for ex.
// libadapter.h
namespace myns
{
template <typename T> T get_value(const string& key);
// specialize for bool, for ex.
template <bool>
bool get_value(const std::string& key)
{
return library::get_value<Extlib::pool_t::boolean>(key));
}
/* or
template <bool>
auto get_value(const std::string& key)
{
return static_cast<bool>(library::get_value<Extlib::pool_t::boolean>(key))
}
*/
// specialize for float
template <float>
float get_value(const std::string& key)
{
return library::get_value<Extlib::pool_t::float>(key);
}
// ... specialize for other types as well, if necccessary ...
}
then in some .cpp:
#include "libadapter.h"
using myns::get_value;
... use get_value ...
Thanks to #StPiere, I could answer my own question with:
std::undordered_map<std::type_index, int> map_types = {
{std::type_index(typeid(bool)), ExtLib::pool_t::boolean_},
{std::type_index(typeid(long)), ExtLib::pool_t::long_},
{std::type_index(typeid(float)), ExtLib::pool_t::float_},
{std::type_index(typeid(double)), ExtLib::pool_t::double_}
}
template <typename T>
T getValue(std::string key) {
const int TT = map_types[std::type_index(typeid(T))]
return get_value<TT>(key);
};
Related
I am working maintenance on a program with a bunch of different structures that are fundamentally similar. I want to write a template method that utilizes SFINAE to enable calling this method from the client. When I define the template specialization inline, everything works as expected. However, when I try to move the template definition into a separate compilation unit, I run into issues. I am trying to move the template implementation into a separate file in order to enable using forward declarations for most of the dependent classes. The following is an example of what I am attempting to achieve:
// Impl.h
#pragma once
struct A {
struct {
int value;
} valueA;
};
struct B {
struct {
int value;
} valueB;
};
template<typename T>
int GetValue(T const &value);
// Impl.cpp
#include "Impl.h"
#include <type_traits>
using std::enable_if_t;
using std::remove_reference_t;
template<typename T, typename U, U(T::*Value)>
static inline int GetValueImpl(T const &value) {
return (value.*Value).value;
}
template<typename T>
enable_if_t<T::valueA, int> GetValue(T const &value) {
static constexpr auto T::*const Value = &T::valueA;
typedef remove_reference_t<decltype(value.*Value)> ValueType;
return GetValueImpl<T, ValueType, Value>(value);
}
template<typename T>
enable_if_t<T::valueB, int> GetValue(T const &value) {
static constexpr auto T::*const Value = &T::valueB;
typedef remove_reference_t<decltype(value.*Value)> ValueType;
return GetValueImpl<T, ValueType, Value>(value);
}
template<> int GetValue(A const &); // C2912 here
template<> int GetValue(B const &); // C2912 here
I am using VS2017u2, and am getting error C2912: explicitt specialization 'int GetValue(const A &)' is not a specialization of a function template. Does anyone know how to make this work with the definitions in a separate compilation unit?
When you write enable_if_t<T::valueA, int>, it is checking for a static member of T called valueA (Which would presumably be a static constexpr bool valueA = /* true or false */;, like what T::value would mean if T was using T = std::is_same<U, V>; ).
To actually check if it has a member called valueA or valueB, put it in a context where there would be a substitution error if the member didn't exist, or true. Something like:
// Pointers to member variables can never be null
// so these will always be enabled if `valueA` or
// `valueB` exist in the first place
enable_if_t<&T::valueA != nullptr, int>
enable_if_t<&T::valueB != nullptr, int>
// But that also allows pointers to static members
// so if you don't want that, you can do something else.
// Like checking if `&T::member` is a pointer to a member
// (But this is probably overkill as you have a specific set
// of types and none of those names are ever static members
// and if you didn't there is a small caveat with
// an overloaded `operator&` but that doesn't really matter)
enable_if_t<std::is_same_v<decltype(&T::valueA), decltype(T::valueA) T::*>, int>
enable_if_t<std::is_same_v<decltype(&T::valueB), decltype(T::valueB) T::*>, int>
Even after fixing the SFINAE check, you are using the wrong syntax for template instantiation. You should use:
template int GetValue(A const &); // No `<>`
template int GetValue(B const &);
And after that, it still doesn't work because template<typename T> enable_if_t<..., int> GetValue(T const&); and template<typename T> int GetValue(T const&); are different functions, so it is ambiguous which one it should instantiate (as both would work). You need to make both of those into different functions (GetValueImpl2 in my example) and have GetValue declared the same way as in the header:
#include <type_traits>
#include "Impl.h"
using std::enable_if_t;
using std::remove_reference_t;
template<typename T, typename U, U(T::*Value)>
static inline int GetValueImpl(T const &value) {
return (value.*Value).value;
}
template<typename T>
enable_if_t<std::is_same_v<decltype(&T::valueA), decltype(T::valueA) T::*>, int> GetValueImpl2(T const &value) {
static constexpr auto T::*const Value = &T::valueA;
using ValueType = decltype(T::valueA);
return GetValueImpl<T, ValueType, Value>(value);
}
template<typename T>
enable_if_t<std::is_same_v<decltype(&T::valueB), decltype(T::valueB) T::*>, int> GetValueImpl2(T const &value) {
static constexpr auto T::*const Value = &T::valueB;
using ValueType = decltype(T::valueB);
return GetValueImpl<T, ValueType, Value>(value);
}
template<typename T>
int GetValue(T const&value) {
return GetValueImpl2(value);
}
template int GetValue<A>(A const &);
template int GetValue<B>(B const &);
I would like to specialize a function template such that the return type changes depending on the type of the template argument.
class ReturnTypeSpecialization
{
public:
template<typename T>
T Item();
};
// Normally just return the template type
template<typename T>
T ReturnTypeSpecialization::Item() { ... }
// When a float is specified, return an int
// This doesn't work:
template<float>
int ReturnTypeSpecialization::Item() { ... }
Is this possible? I can't use C++11.
Since the specialization has to agree with the base template on the return type, you can make it so by adding a "return type trait", a struct you can specialize and draw the true return type from:
// in the normal case, just the identity
template<class T>
struct item_return{ typedef T type; };
template<class T>
typename item_return<T>::type item();
template<>
struct item_return<float>{ typedef int type; };
template<>
int item<float>();
Live example.
Note that you might want to stick to the following, so you only need to update the return-type in the item_return specialization.
template<>
item_return<float>::type foo<float>(){ ... }
// note: No `typename` needed, because `float` is not a dependent type
Do all of the specialization in a worker class and use a simple function as a wrapper that will be specialized implicitly.
#include <iostream>
using std::cout;
// worker class -- return a reference to the given value
template< typename V > struct worker
{
typedef V const & type;
static type get( V const & v ) { return v; }
};
// worker class specialization -- convert 'unsigned char' to 'int'
template<> struct worker<unsigned char>
{
typedef int type;
static type get( unsigned char const & v ) { return v; }
};
// mapper function
template< typename V > typename worker<V>::type mapper( V const & v )
{
return worker<V>::get(v);
}
int main()
{
char a='A';
unsigned char b='B';
cout << "a=" << mapper(a) << ", b=" << mapper(b) << "\n";
}
In this example, the specialization of unsigned char causes it to be converted to an int so that cout will display it as a number instead of as a character, generating the following output...
a=A, b=66
Perhaps you could use the following hack. Given these simple type traits:
template<bool b, typename T, typename U>
struct conditional { typedef T type; };
template<typename T, typename U>
struct conditional<false, T, U> { typedef U type; };
template<typename T, typename U>
struct is_same { static const bool value = false; };
template<typename T>
struct is_same<T, T> { static const bool value = true; };
You could write your class and specialized member function as follows:
class ReturnTypeSpecialization
{
public:
template<typename T>
typename conditional<is_same<T, float>::value, int, T>::type
Item();
};
// Normally just return the template type
template<typename T>
typename conditional<is_same<T, float>::value, int, T>::type
ReturnTypeSpecialization::Item() { return T(); }
// When a float is specified, return an int
template<>
int ReturnTypeSpecialization::Item<float>() { return 1.0f; }
Simple test program (uses C++11 just for verification):
int main()
{
ReturnTypeSpecialization obj;
static_assert(std::is_same<decltype(obj.Item<bool>()), bool>::value, "!");
static_assert(std::is_same<decltype(obj.Item<float>()), int>::value, "!");
}
Here is a live example.
You can do template specializations like so:
template<typename T>
T item() {
return T();
}
template<>
float item<float>() {
return 1.0f;
}
Hi I tried to use the template specialization for returning the parameter value for primitives as well as std::string data, while doing so I was getting lot of unresolved external, redefinition kind of errors.
so if any one face something like this, he/she can use something like below when want to return different data types including string,
NOTE: both the Template function must be the part of the Header file (*.h)...
so we are using template specialization string data type here...
inside class as a inline member we have to use template specialize method and in the same file we can define the template as well.
class ConfigFileParser
{
public:
bool ParseConfigFile(const std::string& file_name);
template <typename T>
T GetParameterValue(const std::string key);
template <>
std::string GetParameterValue<std::string>(const std::string key)
{
std::string param_val = "";
//do logical operation here...
return param_val;
}
private:
// private functions...
// private data...
};
template <typename T>
T ConfigFileParser::GetParameterValue(const std::string key)
{
T param_val = 0;
std::stringstream ss;
std::string val_str;
// do some operation here...
ss << val_str.c_str();
ss >> param_val;
return param_val;
}
Is there a better way of doing the following?
I have a vector class, with the following function:
template <typename T>
bool Vector3<T>::IsUnitVector() const
{
return IsAlmostEqual(this->GetLength(), One<T>::Value());
}
As T can be float or double (I'm using explicit template instantiation to make sure only these types are supported), I've had to create a helper class, which returns the value of 1, in the correct type:
template <typename T>
struct One
{
static T Value();
};
template <>
struct One<int>
{
static int Value() { return 1; }
};
template <>
struct One<float>
{
static float Value() { return 1.0f; }
};
template <>
struct One<double>
{
static double Value() { return 1.0; }
};
This wasn't too bad until I realised I need to create a Zero class as well for other comparisons. So my question is, is there a better way of achieving this?
return IsAlmostEqual(this->GetLength(), static_cast<T>(1));
Small, nonnegative integer values should all be exactly representable by each of the numeric types, so simply static_cast'ing to the desired type should be sufficient.
Alternatively, assuming IsAlmostEqual is a static member function that has two parameters of type T (e.g. as IsAlmostEqual(T lhs, T rhs)), simply let the compiler perform the conversion automatically in the function call:
return IsAlmostEqual(this->GetLength(), 1);
Why not just let the compiler do the conversion work
template<typename T, int val>
bool Vector3<T>::_isConstant()const{
return IsAlmostEqual(this->GetLength(), val);
}
template <typename T>
bool Vector3<T>::IsUnitVector() const{
return _isConstant<T,1>();
}
template<typename T>
bool Vector3<T>::IsZeroVector()const{
return _isConstant<T,0>();
}
not sure if syntax is correct, but thats the general idea.
template <typename T>
struct Value
{
static T Zero();
static T One();
};
template <>
struct Value<int>
{
static int Zero() { return 0; }
static int One() { return 1; }
};
// .. and so on
Please consider the following example:
#include <string>
#include <vector>
using std::string;
using std::vector;
template <typename T>
const T GetValue()
{
return T(); // some value
}
template <typename T>
const vector<T> GetValue()
{
return vector<T>(); // some vector of values
}
int main(int argc, char* argv[])
{
int i = GetValue<int>();
vector<int> = GetValue<vector<int>>();
return 0;
}
I have two template functions which are supposed to parse values from some storage depending on an given type. The first should do the job for simple data types, the second for vectors of simple data types only.
My problem is that the template matching is ambiguous since T may be vector<T>.
I wonder how to implement the overload/specialization for the vector types properly.
Any help would be greatly appreciated!
One simple way is to use an out-param, so that the template parameter can be deduced from the argument:
#include <vector>
using std::vector;
template <typename T>
void GetValue(T &t)
{
t = T(); // some value
}
template <typename T>
void GetValue(vector<T> &v)
{
v = vector<T>(); // some vector of values
}
int main(int argc, char* argv[])
{
int i;
GetValue(i);
vector<int> v;
GetValue(v);
return 0;
}
GetValue(v) isn't ambiguous, since the template argument deduction rules say that the second overload is the better match.
This isn't necessarily the interface/style you want, though, in which case you could use partial specialization instead of overloading. But that requires a class, since function templates cannot be partially specialized:
#include <vector>
using std::vector;
template <typename T>
struct Getter {
T get(void) {
return T(); // some value
}
};
template <typename T>
struct Getter<vector<T> > {
vector<T> get(void) {
return vector<T>(); // some vector of values
}
};
template <typename T>
T GetValue(void)
{
return Getter<T>().get();
}
int main(int argc, char* argv[])
{
int i = GetValue<int>();
vector<int> v = GetValue<vector<int> >();
return 0;
}
Both version ofGetValue differs by only return type, hence it is not overload.
I would suggest you to have just one GetValue and then implement two functions which differ by parameter type, as opposed to return type, and forward the call as:
namespace details
{
template <typename T>
T FillValue(T*)
{
//your code
}
template <typename T>
vector<T> FillValue(vector<T> *)
{
//your code
}
}
template <typename T>
T GetValue()
{
return details::FillValue((T*)0); //pass null pointer of type T*
}
The correct FillValue will be selected by the compiler based on the type of the argument passed to the function, which is T*. If T is vector<U> for some type U, then the second function will be selected, otherwise the first function will be selected.
You can move the partial specialization to a helper class:
#include <vector>
template <typename T>
class Creator {
public:
T operator()() const { return T(); }
};
template <typename T>
class Creator<std::vector<T> > {
public:
std::vector<T> operator()() const { return std::vector<T>(); }
};
template <typename T>
T GetValue() {
return Creator<T>()();
}
int main() {
int i = GetValue<int>();
std::vector<char> v = GetValue<std::vector<char> >();
}
Put the general method inside a class (naming as GetValue preferably) and declare that method as operator T(). Now specialize the class for vector<T>:
template <typename T>
struct GetValue
{
operator const T () const
{
std::cout<<"GetValue()\n";
return T(); // some value
}
};
template <typename T>
struct GetValue<vector<T> >
{
operator const vector<T> ()
{
std::cout<<"GetValue<vector<T>>()\n";
return vector<T>(); // some vector of values
}
};
Usage:
int i = GetValue<int>();
vector<int> v = GetValue<vector<int> >();
Demo
Is it possible to call a function defined in a non-specialised template class from a specialised template class? Here is an example of what i am attempting:
template <typename T>
struct Convert
{
static inline void toString(unsigned num, unsigned places, std::string& str) { ... }
};
template <>
struct Convert<int8_t>
{
static inline void toString(unsigned num, std::string& str)
{
Convert<int8_t>::toString(num, digitis(num), str);
}
};
GCC complains that it can't see the non-specialised class function; i.e. I guess it only looks within the specialised class.
Any thoughts?
EDIT
Here is a more concrete example from my code (with a possible solution):
struct NonSpecial { };
template <typename T>
class Convert
{
template <typename R>
static inline R fromString(const register char *str, const unsigned str_len)
{
R result = 0;
//convert str to R
return result;
}
friend class Convert<int8_t>;
friend class Convert<uint8_t>;
}
template <>
struct Convert<int8_t>
{
static inline int8_t fromString(const register char* str, const unsigned str_len = 4)
{
Convert<NonSpecial>::fromString<int8_t>(str, str_len);
}
};
template <>
struct Convert<uint8_t>
{
static inline uint8_t fromString(const register char* str, const unsigned str_len = 3)
{
Convert<NonSpecial>::fromString<uint8_t>(str, str_len);
}
};
I have other functions - toString(), countDigits(), etc. I have chosen this approach so I can keep the same function names for each type (i.e. don't need toStringU32(), toString32, etc.). I considered template specialization but I don't believe this is possible.
In general, this isn’t possible.
There are different possible solutions but they “cheat”. The first is to hoist off the actual default logic into a different function that is not specialized. Now you can call this function from both toString implementations.
The second alternative entails inheriting from the non-specialized class and passing a special tag as the template argument:
struct BaseClassTag { };
template <>
struct Convert<int8_t> : public Convert<BaseClassTag>
{
typedef Convert<BaseClassTag> TBase;
static inline void toString(unsigned num, std::string& str)
{
TBase::toString(num, digitis(num), str);
}
};