This question already has answers here:
C++ template constructor
(10 answers)
Closed 7 years ago.
I have recently adopted the pattern of Almost Always Auto in C++14, but have come across a case that I can't figure out how to write using the auto syntax: templated constructors.
Say I have the class:
class my_type{
public:
template<typename T>
my_type(){/* ... */}
};
I tried:
auto var = my_type<float>{};
Which, of course, doesn't work because that presumes my_type is a template and not its constructor.
then how could I use auto syntax to initialize this variable?
Although it isn't really about auto, there is a way to select templated ctors if you want to - you need to cheat, and give them an argument.
struct A {
private:
template <typename T> struct TypeWrapper {};
template <typename T> explicit A(TypeWrapper<T>) {}
public:
template <typename T>
static A make_A() {
return A(TypeWrapper<T>{});
}
};
int main() {
auto i = A::make_A<int>();
auto d = A::make_A<double>();
auto r = A::make_A<A>();
// etc. etc.
}
Related
This question already has answers here:
Restricting templates to only certain classes?
(7 answers)
Closed 2 years ago.
I'd like my template function to accept as an argument only a class that inherits from a base class. I think a code snippet explains it better.
class Base
{
// Some magic
}
class Derived : public Base
{
// Even more magic
}
class Foo
{}
// Is it possible to tell template to accept only classes derived from Base?
template<class T>
do_something(T obj)
{
// Perform some dark magic incantations on obj
}
int main()
{
Foo foo;
Derived derived;
do_something<Derived>(derived); // Normal
do_something<Foo>(foo); // Compilation error if I understand templates correctly
}
Pre-C++20 you can use enable_if coupled with checking is_base_of:
template<class T, std::enable_if_t<std::is_base_of_v<Base, T> && !std::is_same_v<Base, T>, int> = 0>
void do_something(T obj)
{
// Perform some dark magic incantations on obj
}
Note that I've explicitly disallowed the type to be an instance of Base (because is_base_of considers a type to be a base of itself). If you want to allow instances of Base, then remove && !std::is_same_v<Base, T>
Live Demo
In C++20 we can almost directly translate our enable_if into a requires expression:
template<class T>
requires (std::is_base_of_v<Base, T> && !std::is_same_v<Base, T>)
void do_something(T obj)
{
// ...
}
Concepts Demo
Or, if you want to allow instances of Base, you can use the built-in derived_from Concept:
template<class T>
requires std::derived_from<T, Base>
void do_something(T obj)
{
// ...
}
Concepts Demo 2
This question already has answers here:
std:: add_pointer, what the try_add_pointer for in the possible implementation?
(2 answers)
Closed 2 years ago.
I've been hacking around the standard library lately, since I need to implement a subset of it (mostly template stuff) for a system which doesn't have an stdlib implementation.
I came across this "possible implementation", in cppreference:
namespace detail {
template <class T>
struct type_identity { using type = T; }; // or use std::type_identity (since C++20)
template <class T>
auto try_add_pointer(int) -> type_identity<typename std::remove_reference<T>::type*>;
template <class T>
auto try_add_pointer(...) -> type_identity<T>;
} // namespace detail
template <class T>
struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
and I've been wondering why do you need SFINAE here. Isn't this:
template< class T >
struct add_pointer {
typedef typename std::remove_reference<T>::type* type;
};
enough? which instantiation takes the second case of try_add_pointer? I tried to think about it but couldn't think about any such case.
I'm not sure if this is the only bad case, but your implementation fails for so-called "abominable function types":
add_pointer<void() const>::type // hard error instead of void() const
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:
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to use enable_if to enable member functions based on template parameter of class
I have a class template:
template<typename T, size_t N> class Vector
I want to enable constructors for specific N, so I do:
Vector(typename boost::enable_if_c<N==2, T>::type const &e0, T const &e1) {
data[0] = e0;
data[1] = e1;
}
But compiler (MSVC 2010 SP1) gives me an error instead of applying SFINAE. The error is:
error C2039: 'type' : is not a member of 'boost::enable_if_c<B,T>'
with
[
B=false,
T=float
]
What is the problem? Is it a known problem? How can I fix it? Is it the only solution to use static_assert?
Edit: GCC does not succeed either: http://ideone.com/7Ejo8
You can't use enable_if to allow/disallow member functions based on template parameters of the class: enable_if can only be applied on function or class templates.
In your case, the only solution I can think of is specializing the entire class, either using enable_if or more simply with partial specialization. You can put the common members in a common base class, to avoid repeating them:
#include <cstdio>
template<typename T, std::size_t N>
struct VectorCommon
{
std::size_t size() { return N; }
void add(T const & element) { }
};
template <typename T, std::size_t N>
struct Vector : VectorCommon<T, N>
{
};
template <typename T>
struct Vector<T, 2> : VectorCommon<T, 2>
{
Vector(T const & e0, T const & e1) {}
};
int main()
{
//Vector<int, 100> v100(12, 42); // compile error
Vector<char, 2> v2('a', 'b'); // ok
}