Essentially I want a template class with an array whose size is a template parameter, to hold constant content.
Something like:
template<size_t S> struct Foo {
const int bar[S];
Foo(const int(&par)[S]) : bar(par) {
cout << "bar size is " << S << endl;
}
};
auto foo = Foo({1,2,3});
I have been searching and tinkering a bit, and almost have a workaround implemented with an intermediate static method and using std::array:
template<size_t S> struct Baz {
const array<int,S> qux;
Baz(const array<int,S>&par) : qux(par) {
cout << "size is " << S << endl;
}
};
template<size_t S> Baz<S>
GetBaz(const array<int,S>&in) {
return Baz<S>(in);
}
int main() {
auto sample = GetBaz({1,2,3});
return 0;
}
... Which is already quite some boilerplate, but still the std::array does not seem to get constructed from an initialiser list? :-(
prog.cpp: In function 'int main()':
prog.cpp:27:30: error: no matching function for call to 'GetBaz(<brace-enclosed initializer list>)'
auto sample = GetBaz({1,2,3});
Post-DR1591 built-in array bound are now deducible from a braced-init-list, so:
template<size_t S> struct Baz {
const array<int,S> qux;
Baz(const array<int,S>&par) : qux(par) {
cout << "size is " << S << endl;
}
Baz(const int (&par)[S]) : qux(std::experimental::to_array(par)) {}
};
template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
return Baz<S>(in);
}
std::experimental::to_array creates an std::array from a built-in one. See the linked cppreference page for implementation.
You can go built-in arrays all the way, but it's somewhat more annoying:
template<size_t S> struct Baz {
const int bar[S];
template<size_t... Is>
Baz(const int (&par)[S], std::index_sequence<Is...>)
: bar { par[Is]... } {}
Baz(const int (&par)[S]) : Baz(par, std::make_index_sequence<S>()) {}
};
template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
return Baz<S>(in);
}
Not sure if I fully understood the questions. Is that what you are trying to achieve?
#include <iostream>
#include <array>
template<size_t S> struct Baz {
const std::array<int,S> qux;
Baz(const std::array<int,S>& par) : qux(par) {
std::cout << "size is " << qux.size() << std::endl;
}
};
int main() {
auto sample = Baz<5>({1,2,3}); // size = 5, values = 1, 2, 3, 0, 0
return 0;
}
Summary:
Use an std::array instead of a raw array.
Specify the template argument, eg: Baz<5>(...).
Class template arguments are not deduced.
You can do it with a classic C array, but using a variadic constructor
#include <array>
#include <cstddef>
#include <iostream>
using namespace std;
template <size_t S> struct Foo {
const int bar[S];
const std::array<int, S> bar2;
template <typename ... I>
Foo (const I & ... i) : bar {i...}, bar2 {{i...}}
{
cout << "bar size is " << S << " == " <<
(sizeof(bar)/sizeof(bar[0])) << " == " << bar2.size() << endl;
}
};
int main()
{
Foo<3> foo {1,2,3};
auto foo2 = Foo<4>{1,2,3,4};
return 0;
}
Related
I'm trying to make my class be convertible to a function pointer, for a slew of reasons unrelated to this post.
When I try to do this with a non-template class, it works fine. Below, Bar bar; bar(1) correctly compiles, and segfaults as-expected. But Foo<int>; foo(1) doesn't compile at all.
I've tried multiple compilers, and I get: mismatched types 'Args' and 'int'
Any ideas? Live demo: https://wandbox.org/permlink/alSGBssfSd4pHgdl
#include <iostream>
#include <tuple>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
operator Test<Args...>() {
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
operator Test<Args...>() {
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
// foo(1);
Bar bar;
bar(1);
return 0;
}
Tried this awful syntax, too:
template<typename... Args>
(*operator void() const)(Args...) {
return {};
}
You can try this:
#include <iostream>
#include <tuple>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
operator Test<Args...>()
{
std::cout << __FUNCTION__ << std::endl;
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
operator Test<Args...>()
{
std::cout << __FUNCTION__ << std::endl;
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
auto x = static_cast<Test<int, double>>(foo);
Bar bar;
auto y = static_cast<Test<char, float>>(bar);
return 0;
}
When using Visual C++ 2019, I get the following run-time output:
Foo<int>::operator void (__cdecl *)(int,double)
Bar::operator void (__cdecl *)(char,float)
The use of the static_cast is to force the usage of the overloaded operator member functions.
Alternatively, you can also try:
#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
Test<Args...> operator()(int x)
{
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
Test<Args...> operator()(int x)
{
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
auto w = foo.template operator()<int, double>(1);
std::cout << "w: " << typeid(w).name() << std::endl;
auto x = foo(2);
std::cout << "x: " << typeid(x).name() << std::endl;
Bar bar;
auto y = bar.template operator()<char, float>(3);
std::cout << "y: " << typeid(y).name() << std::endl;
auto z = bar(4);
std::cout << "z: " << typeid(z).name() << std::endl;
return 0;
}
When using Visual C++ 2019, I get the following run-time output:
w: void (__cdecl*)(int,double)
x: void (__cdecl*)(void)
y: void (__cdecl*)(char,float)
z: void (__cdecl*)(void)
In this way, the object is now callable and returns a function pointer.
I have the following code:
#include <iostream>
#include <string>
#include <type_traits>
struct Foo
{
int i;
int j;
};
template<typename T, T DEFAULT>
class Bar
{
public:
Bar(): mVal(DEFAULT)
{
std::cout << "Bar constructor with mVal = " << mVal << "\n";
}
~Bar(){}
Bar(const T &i) : mVal(i)
{
std::cout << "Bar constructor with mVal = " << mVal << "\n";
}
Bar &operator=(T const &val)
{
mVal = val;
std::cout << "Bar assignment operator with mVal = " << mVal << "\n";
return *this;
}
explicit operator T() const
{
return mVal;
}
private:
T mVal;
};
int main()
{
std::cout << "Hello \n";
Bar<int, 10> bar1;
}
This is working fine in gcc C++14 as long as the first template parameter in Bar is of an integral type. If I want to do Bar<Foo, {}> the following error message is printed:
on-type template parameters of class type only available with '-std=c++2a' or '-std=gnu++2a'
I already expected that. Changing template<typename T, T DEFAULT> class Bar to template<typename T, T DEFAULT = {}> class Bar leads to the same error.
Also a template specialization template<typename T> class Bar<T, {}> does not work for the same reason.
I also tried to experiment with std::enable_if_t<std::is_integral<T>::value> but could not find a solution that would work.
Is there any possible way to just write Bar<Foo> and not have to write a separate class like template<typename T, T DEFAULT> class BarDefault and template<typename T> class Bar for it?
Template parameters and template arguments - cppreference.com
A non-type template parameter must have a structural type, which is one of the following types (optionally cv-qualified, the qualifiers are ignored):
lvalue reference type (to object or to function);
an integral type;
a pointer type (to object or to function);
a pointer to member type (to member object or to member function);
an enumeration type;
std::nullptr_t; (since C++11)
a floating-point type;
a literal class type with the following properties:
all base classes and non-static data members are public and non-mutable and
the types of all bases classes and non-static data members are structural types or (possibly multi-dimensional) array thereof. (since C++20)
So basically custom structure as template value parameter is available since c++20.
Demo
You can overcome this problem by providing depending template which job is to provide a default value:
https://godbolt.org/z/RFp_xH
#include <iostream>
#include <string>
#include <type_traits>
struct Foo
{
int i = 42;
int j = 4;
};
std::ostream& operator<<(std::ostream& out, const Foo& a)
{
return out << a.i << ',' << a.j;
}
template<typename T>
struct BarDefaultValue
{
constexpr static T value()
{
return T{};
}
};
template<>
struct BarDefaultValue<int>
{
constexpr static int value()
{
return 42;
}
};
template<typename T, typename D = BarDefaultValue<T>>
class Bar
{
public:
Bar(): mVal(D::value())
{
std::cout << "Bar constructor with mVal = " << mVal << "\n";
}
~Bar(){}
Bar(const T &i) : mVal(i)
{
std::cout << "Bar constructor with mVal = " << mVal << "\n";
}
Bar &operator=(T const &val)
{
mVal = val;
std::cout << "Bar assignment operator with mVal = " << mVal << "\n";
return *this;
}
explicit operator T() const
{
return mVal;
}
private:
T mVal;
};
int main()
{
std::cout << "Hello \n";
Bar<int> bar1;
Bar<Foo> bar2;
}
You could make a default value to supply.
template<class T>
constexpr T brace_init_value{};
Then used as:
template<typename T, T DEFAULT = brace_init_value<T> >
class Bar
{
Thanks to #Marek R for his idea.
My solution to the problem is the following code which is compiling with gcc in C++14:
#include <iostream>
#include <string>
#include <type_traits>
template <typename T>
constexpr typename std::enable_if<std::is_class<T>::value, T>::type BarDefaultValue(const int &)
{
return {};
}
template <typename T>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type BarDefaultValue(const int &ret)
{
return static_cast<T>(ret);
}
struct Foo
{
int i;
int j;
};
std::ostream& operator<<(std::ostream& out, const Foo& a)
{
return out << a.i << ',' << a.j;
}
template<typename T, int DEFAULT = 0>
class Bar
{
public:
Bar(): mVal(BarDefaultValue<T>(DEFAULT))
{
std::cout << "Bar constructor with mVal = " << mVal << "\n";
}
~Bar(){}
Bar(const T &i) : mVal(i)
{
std::cout << "Bar constructor with mVal = " << mVal << "\n";
}
Bar &operator=(T const &val)
{
mVal = val;
std::cout << "Bar assignment operator with mVal = " << mVal << "\n";
return *this;
}
explicit operator T() const
{
return mVal;
}
private:
T mVal;
};
int main()
{
std::cout << "Hello \n";
Bar<int, 10> bar1;
Bar<Foo> bar2;
}
The output of this file is:
Hello
Bar constructor with mVal = 10
Bar constructor with mVal = 0,0
I have a class called foo_t that has a member called bar which could be any one of the types std::string, int, std::vector<double>, etc. I would like to be able to ask foo_t which type bar has been assigned to. I decided to use std::variant.
I've written a solution, but I'm not sure if this is a good use of std::variant. I'm not sure if it matters, but I expect the list of types to possibly grow much bigger in the future. I made an enum class to store which type std::variant is assigned to. My first implementation also available on wandbox:
#include <iostream>
#include <variant>
#include <vector>
#include <string>
enum foo_kind_t {
double_list,
name_tag,
number,
unknown
};
template <typename val_t>
struct get_foo_kind_t {
constexpr static foo_kind_t value = unknown;
};
template <>
struct get_foo_kind_t<int> {
constexpr static foo_kind_t value = number;
};
template <>
struct get_foo_kind_t<std::string> {
constexpr static foo_kind_t value = name_tag;
};
template <>
struct get_foo_kind_t<std::vector<double>> {
constexpr static foo_kind_t value = double_list;
};
class foo_t {
public:
foo_t(): kind(unknown) {}
template <typename val_t>
void assign_bar(const val_t &val) {
static_assert(get_foo_kind_t<val_t>::value != unknown, "unsupported assignment");
kind = get_foo_kind_t<val_t>::value;
bar = val;
}
foo_kind_t get_kind() {
return kind;
}
template <typename val_t>
val_t get_bar() {
if (get_foo_kind_t<val_t>::value != kind) {
throw std::runtime_error("wrong kind");
}
return std::get<val_t>(bar);
}
private:
foo_kind_t kind;
std::variant<
int,
std::string,
std::vector<double>
> bar;
};
template <typename val_t>
void print_foo(foo_t &foo) {
std::cout << "kind: " << foo.get_kind() << std::endl;
std::cout << "value: " << foo.get_bar<val_t>() << std::endl << std::endl;
}
int main(int, char*[]) {
// double_list
foo_t b;
std::vector<double> b_val({ 1.0, 1.1, 1.2 });
b.assign_bar(b_val);
std::cout << "kind: " << b.get_kind() << std::endl;
std::cout << "value: vector size: " << b.get_bar<std::vector<double>>().size() << std::endl << std::endl;
// name_tag
foo_t d;
std::string d_val("name");
d.assign_bar(d_val);
print_foo<std::string>(d);
// number
foo_t c;
int c_val = 99;
c.assign_bar(c_val);
print_foo<int>(c);
// unknown
foo_t a;
std::cout << a.get_kind() << std::endl;
return 0;
}
Is this a good way to do it? Is there a way having better performance? Is there a way that requires less code to be written? Is there a way that doesn't require C++17?
If you only need to ask "Is this variant of type X ?" for a single type X, then I recommend that you prefer std::holds_alternative over std::variant::index because the line of code is easier to read and will not have to be updated if the index of the type in the variant changes in the future.
Example:
if (std::holds_alternative<X>(my_variant)) {
std::cout << "Variant is of type X" << std::endl;
}
Using std::variant::index to check stored type at runtime.
There is a solution with type traits
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
using MyVariant = std::variant<int, std::string>;
enum class MyVariantType { integer, string };
template <MyVariantType Type, typename T> struct is_variant_type : std::false_type {};
template <> struct is_variant_type<MyVariantType::integer, int > : std::true_type {};
template <> struct is_variant_type<MyVariantType::string , std::string> : std::true_type {};
template<MyVariantType VT>
bool check_variant_type(const MyVariant& myvar)
{
return std::visit([&](const auto& arg) {
return is_variant_type<VT, std::decay_t<decltype(arg)>>::value;
}, myvar);
}
int main(int argc, char* argv[])
{
MyVariant a = int(10);
MyVariant b = "Hello";
std::cout << check_variant_type<MyVariantType::integer>(a);
std::cout << check_variant_type<MyVariantType::integer>(b);
std::cout << check_variant_type<MyVariantType::string>(a);
std::cout << check_variant_type<MyVariantType::string>(b);
return 0;
}
I'm trying to overload a function inside template struct using friend.
I want to use that to map a type to another type. Here in the code below I want to map the type int to MyType.
Here's what I did so far:
void map(...){} // Worst case
// Here's the class that will overload our function
template<typename Type, typename T>
struct MakeFunction {
friend Type map(T) { return {}; }
};
// Make the function with int?
struct MyType : MakeFunction<MyType, int> {};
int main() {
// The type obtained is void, worst case choosed. The expected result is `MyType` as return type.
std::cout << typeid(decltype(map(int{}))).name() << std::endl;
return 0;
}
Then, I tried that:
template<typename T>
void map(){} // Worst case
// Here's the class that will overload our function
template<typename Type, typename T>
struct MakeFunction {
// Compilation error.
friend Type map<T>() { return {}; }
};
struct MyType : MakeFunction<MyType, int> {};
int main() {
std::cout << typeid(decltype(map<int>())).name() << std::endl;
return 0;
}
But the compilation failed with :
error: defining explicit specialization ’map<T>’ in friend delcaration
How can I change the declaration so the right function is picked? Or is there a way to map types without a ton a boilerplate?
Below code shows how you can define a macro DEFINE_TYPE_MAPPING meeting your needs (this is to some extent a sketch demonstrating the idea):
#include <iostream>
#include <typeinfo>
void map(...){} // Worst case
template<class T> struct TypeMapping;
template<class T>
typename TypeMapping<T>::type map(const T&);
#define DEFINE_TYPE_MAPPING(T, U) \
template<> struct TypeMapping<T> { typedef U type; };
struct MyType {};
DEFINE_TYPE_MAPPING(int, MyType);
DEFINE_TYPE_MAPPING(char, float*);
DEFINE_TYPE_MAPPING(std::ostream, unsigned long);
int main() {
std::cout << typeid(decltype(map(int{}))).name() << std::endl;
std::cout << typeid(decltype(map('c'))).name() << std::endl;
std::cout << typeid(decltype(map(std::cout))).name() << std::endl;
std::cout << typeid(decltype(map(1.0))).name() << std::endl;
return 0;
}
How about:
namespace detail{
// To keep exact type
template <typename> struct tag {};
// The mapping
float map(tag<char>);
MyType map(tag<int>);
char map(tag<const int&>);
// ... and so on
}
template <typename T>
using map_t = decltype(detail::map(detail::tag<T>{}));
And then
int main() {
std::cout << typeid(map_t<int>).name() << std::endl;
std::cout << typeid(map_t<const int&>).name() << std::endl;
}
BACKGROUND
I have a container class that has a std::vector<T> member that I initialize with the constructor that takes size_t n_items. I would like to initialize that vector with my own Zero() function which returns 0; by default, but if static member T::Zero exists I want to return that instead.
In my first attempt, I use expression SFINAE, but that failed due to ambiguous overload since both the generic version of Zero and the Zero have the same signature with no arguments. So now, I'm trying to convert the code into classes with operator().
I think I need to use std::enable_if somehow, but I'm not sure how to go about coding this.
FAILED ATTEMPT
#include <cassert>
#include <iostream>
#include <vector>
template<typename T>
struct Zero
{
T operator() const { return 0; }
};
template<typename T>
struct Zero
{
auto operator() const ->
decltype( T::Zero )
{
return T::Zero;
}
};
struct Foo
{
char m_c;
static Foo Zero;
Foo() : m_c( 'a' ) { }
Foo( char c ) : m_c( c ) { }
bool operator==( Foo const& rhs ) const { return m_c==rhs.m_c; }
friend std::ostream& operator<<( std::ostream& os, Foo const& rhs )
{
os << (char)(rhs.m_c);
return os;
}
};
Foo Foo::Zero( 'z' );
int
main( int argc, char** argv )
{
std::vector<unsigned> v( 5, Zero<unsigned>() );
std::vector<Foo> w( 3, Zero<Foo>() );
for( auto& x : v )
std::cout << x << "\n";
std::cout << "---------------------------------\n";
for( auto& x : w )
{
assert( x==Foo::Zero );
std::cout << x << "\n";
}
std::cout << "ZERO = " << Foo::Zero << "\n";
return 0;
}
#include <string>
#include <iostream>
#include <vector>
#include <type_traits>
namespace detail
{
template<class T, class = decltype(T::zero)>
std::true_type has_zero_impl(int);
template<class T>
std::false_type has_zero_impl(short);
}
template<class T>
using has_zero = decltype(detail::has_zero_impl<T>(0));
template<class T, class = has_zero<T>>
struct zero
{
constexpr static T get() { return T(); }
};
template<class T>
struct zero<T, std::true_type>
{
constexpr static auto get() -> decltype(T::zero)
{ return T::zero; }
};
Usage example:
template<>
struct zero<std::string>
{
static constexpr const char* get()
{ return "[Empty]"; }
};
struct foo
{
int m;
static constexpr int zero = 42;
};
int main()
{
std::cout << zero<int>::get() << "\n";
std::cout << zero<std::string>::get() << "\n";
std::cout << zero<foo>::get() << "\n";
}
Compact version w/o trait:
template<class T>
struct zero
{
private:
template<class X>
constexpr static decltype(X::zero) zero_impl(int)
{ return X::zero; }
template<class X>
constexpr static X zero_impl(short)
{ return X(); }
public:
constexpr static auto get()
-> decltype(zero_impl<T>(0))
{
return zero_impl<T>(0);
}
};
template<>
struct zero<std::string>
{
constexpr static const char* get()
{ return "[Empty]"; }
};
Maybe:
#include <iostream>
#include <vector>
template <typename T>
inline T zero() {
return T();
}
template <>
inline std::string zero<std::string>() {
return "[Empty]";
}
int main() {
std::vector<std::string> v(1, zero<std::string>());
std::cout << v[0] << '\n';
}
I have a half good news: I found a very simple way (leveraging SFINAE), however the output is not exactly what I expected :)
#include <iostream>
#include <string>
#include <vector>
// Meat
template <typename T, typename = decltype(T::Zero)>
auto zero_init_impl(int) -> T { return T::Zero; }
template <typename T>
auto zero_init_impl(...) -> T { return T{}; }
template <typename T>
auto zero_init() -> T { return zero_init_impl<T>(0); }
// Example
struct Special { static Special const Zero; std::string data; };
Special const Special::Zero = { "Empty" };
int main() {
std::vector<int> const v{3, zero_init<int>()};
std::vector<Special> const v2{3, zero_init<Special>()};
std::cout << v[0] << ", " << v[1] << ", " << v[2] << "\n";
std::cout << v2[0].data << ", " << v2[1].data << ", " << v2[2].data << "\n";
return 0;
}
As mentioned, the result is surprising was explained by dyp, we have to be careful not use std::initializer<int> by mistake and then read past the end:
3, 0, 0
Empty, Empty, Empty
Curly brace initialization yields a different result than regular brace initialization (see here) which gives the expected 0, 0, 0. So you have to use regular braces.