This question already has answers here:
Templated check for the existence of a class member function?
(33 answers)
SFINAE To detect non-member function existence
(1 answer)
Closed 6 years ago.
I have defined many objects, and for some of them, i defined a function :
template <typename Ratio>
auto print(const T &t, bool a= true, bool b= true)
{
std::stringstream ss;
// ... do stuff ...
return ss.str();
}
where T is the type of one of the objects for which print is defined. Ratio is used inside the function.
My question is :
Is there a way for a type T to find if this function exists ?
For others uses, i already used templates and SFINAE to detect if a class member method exists. But for my problem here, i can't find the solution ... Anyone ?
Thanks,
Ben
PS : Example of SFINAE use in my code, where i needed to detect if a class member method exists .
static T none() { ... }
/**
* SFINAE for checking id none method exists
*/
template <class T>
static auto hasNoneMethod(int)
-> std::integral_constant<bool, std::is_same<T, decltype(T::none())>::value>;
template <class>
static auto hasNoneMethod(...) -> std::false_type;
/**
* Type-Function
*/
template <typename T>
struct HasNoneMethod: decltype(detail::hasNoneMethod<T>(0)) {
};
You may use something like this:
template <class T>
static auto hasPrintMethod(int)
->std::integral_constant<bool, std::is_class<decltype(print(T()))>::value>;
template <class>
static auto hasPrintMethod(...)->std::false_type;
template <typename T>
struct HasPrintMethod : decltype(hasPrintMethod<T>(0)) {
};
Here the decltype(print(T())) is std::string for classes for which your non-member function is defined, and an erroneous type for other classes. So, according to SFINAE concept, HasPrintMethod<A>::value is equal to true for class A with print function defined and is equal to false otherwise.
Related
This question already has answers here:
C++ function template partial specialization?
(7 answers)
Why function template cannot be partially specialized?
(4 answers)
Closed 2 years ago.
I am very new to modern C++ and am trying to do something as described below, which throws error on partial template specialization but works completely fine on complete specialization.
What am I doing here?
Language version: C++14
Compiler: GreenHills (GHS)
Doesnt work
template<bool isPrefix>
struct my_struct;
template<>
struct my_struct<true> // specializes true
{
... some data members...
char prefix_data[10]
}
template<>
struct my_struct<false> // specializes false
{
... only other data members...
// no prefix data member variable
}
template<bool isEnabled, class T>
void prefixData(const T& data)
{
// performing some operation on T
data.prefix_data[0] = 0x01;
}
// DOES NOT WORK, THROWS COMPILATION ERROR
template<class T>
void prefixData<false, T>(const T& data)
{
// no logic required here
}
However, if I specify complete specialization for the function it works.
This Works
template<>
void prefixData<false, my_struct<false>>(const T& data)
{
}
P.S: I want to avoid run-time polymorphism (abstract class + inheritance) since the code will run on embedded platform with limited resources
I want to avoid explicit specialization of each cases. I have explained here with just isPrefix in my_struct. My actual code contains more template variables.
This question already has answers here:
How to detect the presence and type of a member variable given its name?
(2 answers)
Closed 2 years ago.
template <class T>
void packarg(char* &szBuff, T t)
{
if (????)
{
t.pack(szBuff, 10240, &iTmpSize);
}
else
{
memcpy(szBuff, &t, sizeof(T));
}
}
I Have Code like this, if the type T has interface pack then use pack interface, if not, then memcpy it.
So, the question is how I determine whether Type T has Interface "pack" or not.
PS: I'm using C++11.
What you want to do here is write a traits template to determine whether or not a type has that member and that member is callable with a certain set of parameter types.
#include <type_traits>
// a SFINAE helper
template<typename T, typename...>
using first_t = T;
// by default, the trait is false
template<typename...>
struct has_pack_member : std::false_type {};
// if T has a member pack() callable with argument types Args..., the trait is true
template<typename T, typename... Args>
struct has_pack_member<
first_t<
T,
decltype( std::declval<T>().pack( std::declval<Args>()... ) )
>,
Args...
> :
std::true_type
{};
This trait can be used like such in C++17:
if constexpr ( has_pack_member<T, /*argument types*/>::value ) {
t.pack( /*arguments*/ );
} else {
// do something else
}
Before C++17, you need to implement the if and else branches in two separate function templates with the same name, and conditionally enable one or the other based on whether the trait is true or false.
This question already has answers here:
C++ templates that accept only certain types
(14 answers)
restrict a template function, to only allow certain types
(3 answers)
Template excluding one type
(3 answers)
Template Class C++ - exclude some types
(3 answers)
Closed 3 years ago.
Following Template class type-specific functions, how can I customize my template code to not compile for certain types?
If the question is not clear, take a look at this example.
///** template class ***/
template<typename T>
class testClass{
testClass();
T parameter;
}
template<typename T>
void testClass<T>::print(){cout<<parameter.value<<endl;}
The above class is supposed to work for the following types:
//** types file **/
class paramtype1{
int value;
}
class paramtype2{
int value;
}
class paramtype3{
}
As you see, paramtype3 doesn't have value, so I get a compile error saying that value is not defined. I know that if I want to specialize a template class function for a certain type (s), I need to do:
template<>
void testClass<paramtype1>::print(){cout<<parameter.value<<endl;}
But, is there any way to do the other way around, only excluding some certain types?
If you want enable/disable the full class/struct, you can use SFINAE and partial specialization.
The following is a C++17 example
template <typename T, typename = void>
struct testClass;
template <typename T>
struct testClass<T, std::void_t<decltype(T::value)>>
{
testClass()
{ };
T parameter;
void print()
{ std::cout << parameter.value << std::endl; }
};
If you only want enable/disable the print() function, you have to templatize it; by example
template <typename U = T>
std::void_t<decltype(U::value)> print()
{ std::cout << parameter.value << std::endl; }
or also
template <typename U = T>
std::void_t<decltype(U::value), std::enable_if_t<std::is_same_v<U, T>>>
print()
{ std::cout << parameter.value << std::endl; }
if you want to be sure that nobody can "hijack" the method explicating the template type calling
testClass<paramtype3>{}.print<paramtype1>():
What I would personally do to exclude permissions to use certain types is:
template <class T, class... Ts>
struct is_any : std::disjunction<std::is_same<T, Ts>...> {};
// https://stackoverflow.com/questions/17032310/how-to-make-a-variadic-is-same
template <typename T>
void do_something() {
static_assert(!is_any<T, int, bool>::value, "do_something<T> cannot be used with T as int or bool");
// code here
}
Allows you to add a custom assertion message aswel, making it easy to realise what's wrong.
This question already has answers here:
Checking for existence of an (overloaded) member function
(3 answers)
Closed 5 years ago.
Consider the following, I want to check if the types I pass off to some other function sf has a member function T::mf that is required by sf, I know the return type and the name but there can by any number of overloads.
After some tinkering (well it is fun..) and googling , I can get something like the code below to work, the problem is that I don't know how to express that print can have a variable number of arguments.
#include <type_traits>
#include <utility>
template <typename T,typename = void>
struct has_write : std::false_type {};
template <typename T>
struct has_write<T, decltype(std::declval<T>().write())> : std::true_type {};
template <typename T, typename R = void , typename ...Args>
struct has_print : std::false_type {};
// cant deduce, specialization never used
template <typename T, typename ...Args>
struct has_print<T, decltype(std::declval<T>().print(std::declval<Args>()...))> : std::true_type {};
struct Foo {
void write();
};
struct Bar {
int print(int, float, int);
};
int main(){
static_assert(has_write<Foo>::value, "Does not have write..");
static_assert(has_print<Bar>::value, "Does not have print..");
return 0;
}
The above compiles with g++ but the second assert fails, clang is a bit more helpful and tells me that the specializations for has_print will never be used because it cannot deduce all the types.
Since you will be calling your overload from within sf function, you should check for availability of the particular overload using the types sf function would call it with.
General checking for availability of any overload within a class would always be an XY problem by definition, because availability of any overload is never important. You need to know you can call a name with given set of arguments. Consider this: asking for availability of any overload of a given name is conceptually the same as asking if particular class has any method at all. And obviously you would not be interested in it?
This question already has an answer here:
C++ template typedef
(1 answer)
Closed 8 years ago.
How can I solve this error?
My header file
template<typename T>
class C1 {
public:
typedef std::vector<T::F> TFV;
TFV Function1();
};
My CPP file
template<typename T>
TFV C1::Function() //error: ‘TFV’ does not name a type
{ }
First of all, use the typename keyword to tell the compiler to interpret F as the (qualified) name of a type:
typedef std::vector<typename T::F> TFV;
// ^^^^^^^^
Secondly, TFV is not a type defined in the global namespace, so you have to properly qualify that as well in the definition of Function1():
template<typename T>
typename C1<T>::TFV C1<T>::Function1()
// ^^^^^^^^ ^^^^^^^ ^^^
{ }
Finally, the definition of member functions of a class template should be placed in a header file, unless you are providing explicit instantiations for all the template instantiations you would otherwise implicitly generate.
Failing to do so will most likely result in an unresolved references error from the linker.
Having C++11? Then use trailing return types.
template<typename T>
class C1 {
public:
typedef std::vector<typename T::F> TFV;
TFV Function1();
};
template<typename T>
auto C1<T>::Function1() -> TFV { }
This works because after the parameters of the function, () in this case, the scope is the same as inside the {} block. You have access to this (useful in combination with decltype) and you can use TFV without the scope resolution operator.