#include <cstddef>
#include <utility>
template <size_t N, typename... V>
struct T {
int test(size_t n, const char** ss) {
if (N > n)
return 1;
return []<size_t... I>(const char* ss[N], std::index_sequence<I...>) {
return test_impl(ss[I]...);
}(ss, std::make_index_sequence<N>{});
}
// Ideally this would be templated, solving my problem:
// i.e. move "typename... V" from the struct to this function.
virtual int test_impl(V...) = 0;
};
template <typename U, size_t N, typename... V>
struct T1 : T<N, V...> {
U value;
int (*tester)(U*, V...);
int test_impl(V... v) {
return tester(&value, v...);
}
// virtual is not an aggregate
T1(U value, int (*tester)(U*, V...))
: value{value}, tester{tester}
{};
};
int test1(int* v, const char* s1, const char* s2) {
return 1;
}
template <typename... V>
int test2(int* v, V... ss) {
return 1;
}
C++ is very good at deducing template function parameters from function arguments, but virtual function templates are not allowed. I am forced to move the function template parameters to the struct template, and find that C++ is not good at deducing template struct parameters from member variables. In the end I am forced to specify redundant information to the template which makes the T1/T interface difficult to use? How can I fix this?
For example, here we know that:
sizeof...(V) == N
decltype(V) must be const char*
template parameter U can be deduced solely from the argument of the T1 constructor
template parameter V... can be deduced solely from the argument of the T1 constructor
from which it follows that template parameter N can be deduced solely from the argument of the T1 constructor.
int main() {
// The '2' and the 'const char*'... are redundant
T1 a = T1<int, 2, const char*, const char*>(10, test1);
T1 b = T1<int, 2, const char*, const char*>(10, test2);
// There is enough information here to deduce the values
T1 c = T1(10, test1);
// There is enough information here to deduce the values
T1 d = T1<..., 2, ...>(10, test2);
}
sizeof...(V) == N
No, the compiler doesn't know it. (Take a look at the error messages)
Since you have this prequisite, you don't have to have the template parameter N.
template <typename... V>
struct T {
int test(size_t n, const char** ss) {
constexpr int N = sizeof...(V);
if (N > n)
return 1;
return []<size_t... I>(const char* ss[N], std::index_sequence<I...>) {
return test_impl(ss[I]...);
}(ss, std::make_index_sequence<N>{});
}
// Ideally this would be templated, solving my problem:
// i.e. move "typename... V" from the struct to this function.
virtual int test_impl(V...) = 0;
};
See online demo
Related
I'd like to write a type alias template that resolves to the const of the template parameter for most types, like so:
template <typename T>
using TypeAlias = const T;
but for a particular type, say int, it simply resolves to T.
I've tried doing this with std::conditional, as well as specialization of structs containing the type alias, but in all cases, the compiler is unable to infer the type. My questions are: what am I doing wrong in the examples below? and How does one do this correctly?
Edit: I'm working in a very large codebase that handles a large number of types, and adds const to all of them in the definition of TypeAlias (which is actually a more complicated type, basically a container templated over const T). I'm trying to modify this codebase to accept a new type which cannot be const, while making minimal modifications. Explicitly specifying the type in all templated functions like foo isn't a workable solution. What I'm really looking for is a way to modify TypeAlias, and little to nothing else.
example 1:
#include <stdio.h>
#include <type_traits>
template <typename T>
using TypeAlias = typename std::conditional<std::is_same<int, T>::value,
T, typename std::add_const<T>::type>::type;
template <typename T>
void foo(TypeAlias<T> var) {
printf("var = %f\n", static_cast<double>(var));
}
int main(int argc, char *argv[]) {
const int a = 1;
const float b = 2;
const double c = 3;
foo(a);
foo(b);
foo(c);
return 0;
}
example 2:
template <typename T>
struct TypeHolder {
using type = const T;
};
template <>
struct TypeHolder<int> {
using type = int;
};
template <typename T>
void foo(typename TypeHolder<T>::type var) {
printf("var = %f\n", static_cast<double>(var));
}
int main(int argc, char *argv[]) {
int a = 1;
const float b = 2;
const double c = 3;
foo(a);
foo(b);
foo(c);
return 0;
}
Here's another way to remove const for a specific set of types, just add an overload and use SFINAE to constrain based on whether the deduced type is in the set or not:
#include <iostream>
#include <type_traits>
template <class T, class... Ts>
inline constexpr bool is_any_v = (... || std::is_same_v<T, Ts>);
template <class T>
inline constexpr bool int_or_short_v = is_any_v<T, int, short>;
template <class T>
std::enable_if_t<!int_or_short_v<T>> foo(const T) { std::cout << "const" << std::endl; }
template <class T>
std::enable_if_t<int_or_short_v<T>> foo(T) { std::cout << "non-const" << std::endl; }
int main() {
const int a = 1;
const short b = 2;
const float c = 3;
const double d = 4;
foo(a);
foo(b);
foo(c);
foo(d);
}
Try it on godbolt.org
In C++20, even easier:
#include <iostream>
#include <concepts>
template <class T, class... Ts>
concept any_of = (... || std::same_as<T, Ts>);
void foo(const auto) { std::cout << "const" << std::endl; }
void foo(any_of<int, short> auto) { std::cout << "non-const" << std::endl; }
int main() {
const int a = 1;
const short b = 2;
const float c = 3;
const double d = 4;
foo(a);
foo(b);
foo(c);
foo(d);
}
Try it on godbolt.org
As was mentioned in the comments, this is a non-deduced context so the template types will not be deduced. This is actually one of the tricks you can use to force the caller so explicitly set the template parameter.
What you could do is use if constexpr to differentiate between your two (or more) cases:
void foo_for_int(int x) { /* do something for ints */ }
template <typename T> foo_for_others(T const x) { /* do something for other types */ }
template <typename T>
void foo(T && t)
{
if constexpr (std::is_same_v<int, T>)
{
foo_for_int(t); // no need to forward an int
}
else
{
foo_for_others(std::forward<T>(t));
}
}
Here's what I want to do:
#include <vector>
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp =
[](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;})
{
}
int main()
{
std::vector<int> a{1, 2};
f(a);
return 0;
}
But it doesn't work: could not deduce template argument for 'ComparatorType'.
Using a proxy function instead of an actual default argument value works, but seems overly verbose, isn't there a better way? Not to mention it's not the same since now I can't just substitute the default comparator with my own without changing the function name in the client code.
#include <vector>
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp)
{
}
template <class ContainerType>
void f2(ContainerType c)
{
f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}
int main()
{
std::vector<int> a{1, 2};
f2(a);
return 0;
}
without changing the function name in the client code.
You can overload function templates just fine. There is no need to use a different name.
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp)
{
}
template <class ContainerType>
void f(ContainerType c)
{
f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}
You can't make a default function argument contribute to template argument deduction. It's not allowed because it raises some difficult to resolve questions in the deduction process.
Template deduction is performed before default arguments are considered. Also, lambdas are not allowed to appear in unevaluated operands.
You can first assign the default function to a variable. Then you can spell out its type. For example:
auto default_functor = [](int x){ return x > 0; };
template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
return f(x);
}
Now you can use the function as usual:
bool even(int x)
{
return x % 2 == 0;
}
struct Odd {
bool operator()(int x) const
{
return x % 2 == 1;
}
};
void g()
{
function(1); // use default functor
function(1, even); // use a free function
function(1, Odd{}); // use a function object
function(1, [](int x){ return x < 0; }); // use another lambda
}
You don't need to explicitly specify the type.
Note: According to #StoryTeller, this can lead to ODR violation if you use it in a header. In that case, you can use a named functor type:
struct Positive {
constexpr bool operator(int x) const
{
return x > 0;
}
};
inline constexpr Positive default_functor{};
template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
return f(x);
}
I want to have a struct template, that is defined by particular values of its components passed to it during construction, such that different values would create different C++ data types, and thought non-type template parameters may be useful for that.
Something like this (just a simple example to show the issue, the real struct will be more complex):
enum ElementType
{
TYPE1,
TYPE2
};
template<ElementType elementType, int size>
struct DataType
{
DataType(ElementType et = elementType, int s = size):
elementType_(et),
size_(s)
{
}
ElementType elementType_;
int size_;
};
int main()
{
auto d1 = DataType(ElementType::TYPE1, 1);
}
I try to build this with g++-8 -std=c++17 and it gives me the following error:
./main.cpp:23:42: error: class template argument deduction failed:
auto d1 = DataType(ElementType::TYPE1, 1);
^
../main.cpp:23:42: error: no matching function for call to ‘DataType(ElementType, int)’
../main.cpp:12:2: note: candidate: ‘template<ElementType elementType, int size> DataType(ElementType, int)-> DataType<elementType, size>’
DataType(ElementType et = elementType, int s = size):
^~~~~~~~
../main.cpp:12:2: note: template argument deduction/substitution failed:
../main.cpp:23:42: note: couldn't deduce template parameter ‘elementType’
auto d1 = DataType(ElementType::TYPE1, 1);
^
../main.cpp:23:42: error: expression list treated as compound expression in functional cast [-fpermissive]
../main.cpp:23:42: warning: left operand of comma operator has no effect [-Wunused-value]
Note that I cannot use type template arguments, since the two types of the arguments are fixed (ElementType and int), but DataType(ElementType::TYPE1, 1) must be of different type than DataType(ElementType::TYPE1, 2) and DataType(ElementType::TYPE1, 1) must be different than DataType(ElementType::TYPE2, 1).
You can define your template like this:
template<ElementType elementType, int size>
struct DataType
{
const ElementType elementType_ = elementType;
const int size_ = size;
};
And create an instance of it like this:
auto d1 = DataType<ElementType::TYPE1, 1>();
Demo
To make use of deduction the value you pass to the constructor needs to be a constant expression. Unfortunately values passed as parameter loose their constexpr properties. To prevent this behavior you can pass the values wrapped in types e.g. using std::integral_constant.
Exemplary usage:
#include <type_traits>
enum ElementType
{
TYPE1,
TYPE2
};
template<ElementType elementType, int size>
struct DataType
{
DataType(std::integral_constant<ElementType, elementType>, std::integral_constant<int, size> ic):
elementType_(elementType),
size_(ic)
{
}
ElementType elementType_;
int size_;
};
int main()
{
auto d1 = DataType(std::integral_constant<ElementType, TYPE1>{}, std::integral_constant<int, 1>{});
}
[live demo]
To make it more convenient to use you could wrap around integral const with constexpr suffix operators:
#include <type_traits>
enum ElementType
{
TYPE1,
TYPE2
};
template <class... Ts>
constexpr int ival(Ts... Vs) {
char vals[sizeof...(Vs)] = {Vs...};
int result = 0;
for (int i = 0; i < sizeof...(Vs); i++) {
result *= 10;
result += vals[i] - '0';
}
return result;
}
template <class T, class... Ts>
constexpr ElementType etval(T V, Ts... Vs) {
if (V == '1')
return TYPE1;
if (V == '2')
return TYPE2;
}
template <char... Vs>
std::integral_constant<int, ival(Vs...)> operator""_i() {
return {};
}
template <char... Vs>
std::integral_constant<ElementType, etval(Vs...)> operator""_et() {
return {};
}
template<ElementType elementType, int size>
struct DataType
{
DataType(std::integral_constant<ElementType, elementType>, std::integral_constant<int, size> ic):
elementType_(elementType),
size_(ic)
{
}
ElementType elementType_;
int size_;
};
int main()
{
auto d1 = DataType(1_et, 1_i);
}
[live demo]
Problem description:
C++17 introduces std::invocable<F, Args...>, which is nice to detect if a type... is invocable with the given arguments. However, would there be a way to do it for any arguments for functors (because combinations of the existing traits of the standard library already allow to detect functions, function pointers, function references, member functions...)?
In other words, how to implement the following type trait?
template <class F>
struct is_functor {
static constexpr bool value = /*using F::operator() in derived class works*/;
};
Example of use:
#include <iostream>
#include <type_traits>
struct class0 {
void f();
void g();
};
struct class1 {
void f();
void g();
void operator()(int);
};
struct class2 {
void operator()(int);
void operator()(double);
void operator()(double, double) const noexcept;
};
struct class3 {
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
union union0 {
unsigned int x;
unsigned long long int y;
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
struct final_class final {
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
int main(int argc, char* argv[]) {
std::cout << is_functor<int>::value;
std::cout << is_functor<class0>::value;
std::cout << is_functor<class1>::value;
std::cout << is_functor<class2>::value;
std::cout << is_functor<class3>::value;
std::cout << is_functor<union0>::value;
std::cout << is_functor<final_class>::value << std::endl;
return 0;
}
should output 001111X. In an ideal world, X should be 1, but I don't think it's doable in C++17 (see bonus section).
Edit:
This post seems to present a strategy that solves the problem. However, would there be a better/more elegant way to do it in C++17?
Bonus:
And as a bonus, would there be a way to make it work on final types (but that's completely optional and probably not doable)?
Building on my answer to my answer to this qustion, i was able to solve your problem, including the bonus one :-)
The following is the code posted in the other thread plus some little tweaks to get a special value when an object can't be called. The code needs c++17, so currently no MSVC...
#include<utility>
constexpr size_t max_arity = 10;
struct variadic_t
{
};
struct not_callable_t
{
};
namespace detail
{
// it is templated, to be able to create a
// "sequence" of arbitrary_t's of given size and
// hece, to 'simulate' an arbitrary function signature.
template <size_t>
struct arbitrary_t
{
// this type casts implicitly to anything,
// thus, it can represent an arbitrary type.
template <typename T>
operator T&& ();
template <typename T>
operator T& ();
};
template <typename F, size_t... Is,
typename U = decltype(std::declval<F>()(arbitrary_t<Is>{}...))>
constexpr auto test_signature(std::index_sequence<Is...>)
{
return std::integral_constant<size_t, sizeof...(Is)>{};
}
template <size_t I, typename F>
constexpr auto arity_impl(int) -> decltype(test_signature<F>(std::make_index_sequence<I>{}))
{
return {};
}
template <size_t I, typename F, std::enable_if_t<(I == 0), int> = 0>
constexpr auto arity_impl(...) {
return not_callable_t{};
}
template <size_t I, typename F, std::enable_if_t<(I > 0), int> = 0>
constexpr auto arity_impl(...)
{
// try the int overload which will only work,
// if F takes I-1 arguments. Otherwise this
// overload will be selected and we'll try it
// with one element less.
return arity_impl<I - 1, F>(0);
}
template <typename F, size_t MaxArity = 10>
constexpr auto arity_impl()
{
// start checking function signatures with max_arity + 1 elements
constexpr auto tmp = arity_impl<MaxArity + 1, F>(0);
if constexpr(std::is_same_v<std::decay_t<decltype(tmp)>, not_callable_t>) {
return not_callable_t{};
}
else if constexpr (tmp == MaxArity + 1)
{
// if that works, F is considered variadic
return variadic_t{};
}
else
{
// if not, tmp will be the correct arity of F
return tmp;
}
}
}
template <typename F, size_t MaxArity = max_arity>
constexpr auto arity(F&& f) { return detail::arity_impl<std::decay_t<F>, MaxArity>(); }
template <typename F, size_t MaxArity = max_arity>
constexpr auto arity_v = detail::arity_impl<std::decay_t<F>, MaxArity>();
template <typename F, size_t MaxArity = max_arity>
constexpr bool is_variadic_v = std::is_same_v<std::decay_t<decltype(arity_v<F, MaxArity>)>, variadic_t>;
// HERE'S THE IS_FUNCTOR
template<typename T>
constexpr bool is_functor_v = !std::is_same_v<std::decay_t<decltype(arity_v<T>)>, not_callable_t>;
Given the classes in yout question, the following compiles sucessfully (you can even use variadic lambdas:
constexpr auto lambda_func = [](auto...){};
void test_is_functor() {
static_assert(!is_functor_v<int>);
static_assert(!is_functor_v<class0>);
static_assert(is_functor_v<class1>);
static_assert(is_functor_v<class2>);
static_assert(is_functor_v<class3>);
static_assert(is_functor_v<union0>);
static_assert(is_functor_v<final_class>);
static_assert(is_functor_v<decltype(lambda_func)>);
}
See also a running example here.
I'm trying to make a C++ function that accepts an unknown number of parameters total, but that they are always paired with specific types.
// logically, this is what the template Pair would be
// template<int, std::string> struct Pair {};
// desired:
// accept a const char * as a first parameter, and then in pairs ...
// integer, const char *
template <typename... Arguments> unsigned int onlyInPairs
(const std::string name, const Arguments& ... args) {
const unsigned numargs = sizeof...(Arguments);
// more magic would happen here with the parameters :)
return numargs;
}
int _tmain(int argc, _TCHAR* argv[])
{
// only string, [num, string] [num, string] should work
// desire that the syntax be as simple as shown, and not require
// extra classes to be created (like a Tuple) for each pair.
// this should work...
auto count = onlyInPairs("ABC", 1, "DEF", 2, "HIJ"); // works
// this should not work, as it's not number, string
count = onlyInPairs("ABC", 1, "DEF", "NOTRIGHT", 2);
return 0;
}
I've looked at parameter packs (reference), but can't seem to apply the documentation I've found to my specific problem. I'd like to try to catch the problem at compile time if the parameters are not specified correctly.
The goal was to use a syntax that was free of template noise as much as possible as the "pairs" will always be this way (and the programmer will know that). So, we wanted to just have int, string (repeat).
Ideally, the solution would work with Visual Studio 2013's C++ compiler, but I'd accept any answer that works and demonstrates the current possible shortcomings of VS C++ related to this issue.
Appendix - More details
The code being written would ultimately be often read by tech-savvy, but not formally trained C/C++ programmers (like a technical support). So, we're trying to get it to be distraction free as much as possible. There can be 2-16 pairs of values ... so keeping it distraction free and just the data is desirable.
Here's one possibility. Class template Enforce recursively inherits from itself and applies static_assert on pairs of template arguments until the specialization is picked that doesn't do anything:
#include <type_traits>
#include <string>
template<typename...Args>
struct Enforce;
template<typename T, typename T1, typename T2, typename... Args>
struct Enforce<T, T1, T2, Args...> : Enforce<T, Args...> {
static_assert( std::is_constructible<T, T2>::value, "Wrong T2!");
};
template<typename T>
struct Enforce<T> {
};
template <typename... Arguments>
void onlyInPairs (const std::string name, const Arguments& ... args)
{
Enforce<std::string, Arguments...>();
}
int main()
{
onlyInPairs("this", 1, "works", 2, "fine");
//onlyInPairs("this", 1, "doesn't", 2, 3);
}
Instead of recursive inheritance, you can use recursive typedef instead. At least in gcc, that ought to compile faster and with less noise (warning about non-virtual destructor in base class, etc.).
EDIT:
Here's another version that ANDs the checks together and saves the result:
template<typename...Args>
struct Enforce;
template<typename T, typename T1, typename T2, typename... Args>
struct Enforce<T, T1, T2, Args...> {
static const bool value =
std::is_constructible<T,T2>::value &&
Enforce<T, Args...>::value;
};
template<typename T>
struct Enforce<T> : std::true_type {
};
Now you can move the assert closer, inside onlyInPairs:
template <typename... Arguments>
void onlyInPairs (const std::string name, const Arguments& ... args)
{
static_assert( Enforce<std::string, Arguments...>::value , "Wrong second arg..." );
}
What template noise do you speak of?
void onlyInPairs(std::initializer_list<std::pair<int, std::string>>&& pairs) {}
int main() {
onlyInPairs({
{1, "abc"},
{2, "def"},
{3, "foo"},
});
}
Use compile time recursion:
void processArgPairs() {
// to stop recursion
}
template <typename Arg1, typename Arg2, typename... Arguments>
void processArgPairs(Arg1 a, Arg2 b, Arguments&& ...args){
static_assert(std::is_constructible<int, Arg1>::value, "Wrong type of first argument - int expected");
static_assert(std::is_constructible<std::string, Arg2>::value, "Wrong type of second argument - string expected
processArgPairs(std::forward<Arguments>(args)...);
}
template <typename... Arguments> unsigned int onlyInPairs
(const std::string name, Arguments&& ... args) {
const unsigned numargs = sizeof...(Arguments);
processArgPairs(std::forward<Arguments>(args)...);
return numargs;
}
Something like this?
template <typename... Arguments>
unsigned int onlyInPairs(const std::string name, const Arguments& ... args)
{
const unsigned numargs = sizeof...(Arguments);
check(args...);
return numargs;
}
template <typename... Arguments>
void check(const int i, const std::string name, const Arguments& ... args)
{
check(args...);
}
void check(const int i, const std::string name)
{
}
int main()
{
auto count = onlyInPairs("ABC", 1, "DEF", 2, "HIJ"); // works
count = onlyInPairs("ABC", 1, "DEF", "NOTRIGHT", 2); //compile error
return 0;
}
This is a fairly old-school solution: using is_convertible should be cleaner
#include <string>
template <typename... Args> struct EnforcePairsHelper;
// terminal case
template <> struct EnforcePairsHelper<> {
enum { size = 0 };
};
// multiple specializations for reliable matching:
// only the last is really required here
template <typename... ArgTail>
struct EnforcePairsHelper<int, const char *, ArgTail...> {
enum { size = 2 + EnforcePairsHelper<ArgTail...>::size };
};
template <typename... ArgTail>
struct EnforcePairsHelper<int, char *, ArgTail...> {
enum { size = 2 + EnforcePairsHelper<ArgTail...>::size };
};
template <int N, typename... ArgTail>
struct EnforcePairsHelper<int, char [N], ArgTail...> {
enum { size = 2 + EnforcePairsHelper<ArgTail...>::size };
};
template <typename... Args> unsigned onlyInPairs (const std::string name,
const Args& ... args) {
const unsigned numargs = EnforcePairsHelper<Args...>::size;
// more magic would happen here with the parameters :)
return numargs;
}
int main() {
unsigned ok = onlyInPairs("ABC", 1, "DEF", 2, "HIJ");
// unsigned no = onlyInPairs("ABC", 1, "DEF", "NOTRIGHT", 2);
}