多个模板相关参数

问题描述 投票:0回答:2

我不确定问题名称是否真的反映了我在这里问的问题,所以如果有更好的标题,请告诉我。

我有一个代表一个值的类,它可以通过可调用对象初始化,或者更干净地通过对变量的引用来初始化。

template <typename F> concept not_callable = !std::invocable<F>;

template <typename... Args>
struct Values{
  std::tuple<std::function<Args()>...> values;

  Values(std::invocable auto&&... func): values{std::make_tuple(std::function(func)...)} {}
  Values(not_callable auto&... args): values{std::make_tuple(std::function([&args](){return args;})...)} {}
};

Values(std::invocable auto&&... func) -> Values<std::remove_cvref_t<decltype(func())>...>;
Values(not_callable auto&... arg) -> Values<std::remove_cvref_t<decltype(arg)>...>;

这使我可以通过一系列函数或引用来构造函数。但是,我希望能够混合使用这些来初始化它。

int x;
char* y;
Values v1 (rand, clock);
Values v2 (x, y);
// Values v3 (x, rand); Doesn't work

请注意,现在它失败了,因为我对构造函数的概念存在冲突,不允许将两者一起初始化。但是,如果没有这些概念,它们根本无法编译。有没有办法让这项工作?

另一种解决方案是让此类包含另一个类的元组,其中该类可从单个 var 或可调用对象构造。

不幸的是,这需要像下面这样的语法,并对每个参数进行显式转换。

class singleV;
Value v4(singleV(x), singleV(rand)); 

有没有办法像

v3
一样初始化它?

c++ templates c++20 variadic-templates c++-concepts
2个回答
0
投票

可以定义辅助函数,根据参数的类型构造对应的

std::function
对象

template <typename T> 
concept callable_or_variable = 
  std::invocable<T> || std::is_lvalue_reference_v<T>;

template <callable_or_variable T>
auto to_function(T&& t) {
  if constexpr (std::invocable<T>)
    return std::function<std::remove_cvref_t<std::invoke_result_t<T>>()>(t);
  else
    return std::function<std::remove_cvref_t<T>()>([&t] { return t; });
}

然后根据这个辅助函数返回的

std::function
类型的返回类型实现CTAD

template <typename... Args>
struct Values{
  std::tuple<std::function<Args()>...> values;

  Values(callable_or_variable auto&&... args): 
    values{to_function(std::forward<decltype(args)>(args))...} {}
};

template <callable_or_variable... Args>
Values(Args&&...) -> 
    Values<std::invoke_result_t<decltype(to_function(std::declval<Args>()))>...>;

演示


0
投票

目前,你有两个构造函数,一个只接受

std::invocable
参数,另一个只接受non-
std::invocable
左值引用参数。首先,我们可以用不简洁的语法写出来:

template<class... T>
requires (std::invocable<T> and...)
Values(T&&... func);

template<class... T>
requires ((not std::invocable<T> and std::is_lvalue_reference_v<T>) and...)
Values(T&&... args);

然后我们可以将它们组合成一个构造函数:

template<class... T>
requires (std::invocable<T> and...) or ((not std::invocable<T> and std::is_lvalue_reference_v<T>) and...)
Values(T&&...);

然后,翻转逻辑,这样我们就有了析取的合取,而不是连取的析取:

template<class... T>
requires ((std::invocable<T> or (not std::invocable<T> and std::is_lvalue_reference_v<T>) and...)
Values(T&&...);

这处理了构造函数的声明,现在剩下的就是define了。

对于构造函数初始化器,您可以使用例如生活:

template<class... T>
requires ((std::invocable<T> or (not std::invocable<T> and std::is_lvalue_reference_v<T>) and...)
Values(T&&... args) : values{[&] {
    if constexpr (std::invocable<T>)
        return args;
    else
        return [&args] { return args; }
}()...} {}

对于 ctad 指南也是如此:

template<class... T>
requires ((std::invocable<T> or (not std::invocable<T> and std::is_lvalue_reference_v<T>) and...)
Values(T&&... args) -> Values<std::remove_cvref_t<decltype([]{
    if constexpr (std::invocable<T>)
        return args();
    else
        return args;
}())>...>;
© www.soinside.com 2019 - 2024. All rights reserved.