【问题标题】:How to check if a class if explicitly constructible from multiple arguments?如何检查一个类是否可以从多个参数显式构造?
【发布时间】:2020-07-17 22:48:57
【问题描述】:

有没有一种好方法来评估是否存在多个参数的显式构造函数?这与question 非常相似,除了std::is_convertible 不适用于这种情况,因为我们有多个参数传递给我们正在测试的构造函数。

例如:

#include <iostream>
#include <type_traits>

struct InitParams
{
    int Parameter1;
    int Parameter2;
};

class ExampleFloatConstructible
{
public:
    explicit ExampleFloatConstructible(float InValue, const InitParams& InParams);
};

class ExampleIntConstructible
{
public:
    explicit ExampleIntConstructible(int InValue, const InitParams& InParams);
};

template<typename ClassToTest, typename ArgType>
struct IsExplicitlyConstructibleWithSettings
{
    static constexpr bool value = std::is_constructible<ClassToTest, ArgType, const InitParams&>::value;
};

int main()
{
    // "Correct" values:
    // will be true:
    std::cout << "ExampleFloatConstructible Can Be Built from float? " << 
        IsExplicitlyConstructibleWithSettings<ExampleFloatConstructible, float>::value << std::endl;
    
    // will be true:
    std::cout << "ExampleIntConstructible Can Be Built from int? " << 
        IsExplicitlyConstructibleWithSettings<ExampleIntConstructible, int>::value << std::endl; 

    // "Incorrect" values:
    // will also be true, because int is convertible from float
    std::cout << "ExampleIntConstructible Can Be Built from float? " <<  
        IsExplicitlyConstructibleWithSettings<ExampleIntConstructible, float>::value << std::endl;

    // will also be true, because float is convertible from int
     std::cout << "ExampleFloatConstructible Can Be Built from int? " << 
        IsExplicitlyConstructibleWithSettings<ExampleFloatConstructible, int>::value << std::endl; 
}

Here's the above example in compiler explorer.

【问题讨论】:

  • is_convertible 将如何处理多个参数?
  • @CleitonSantoiaSilva,这就是问题的重点。
  • 好吧,如果你的调用有多个参数,那么你甚至不需要问“is_convertible”对吗?
  • @CleitonSantoiaSilva,如果你不做那一半,你会考虑隐式+显式转换。发帖人希望在测试中禁止隐式转换。
  • @CleitonSantoiaSilva is_convertible 刚刚提到了另一个问题,该问题能够使用 is_convertible 来测试具有一个参数的构造函数是否存在显式构造函数:stackoverflow.com/questions/42786565/…

标签: c++ templates c++17 sfinae


【解决方案1】:

不幸的是,我认为您必须制作自己的版本,将 {args} 传递给假装函数而不是 arg (live example):

// Can we call this function with {args}?
template<typename To>
void conversion_test(To);

// If passing {From...} as an arg to conversion_test<To> fails, return false.
template<typename To, typename... From>
constexpr bool sfinae_helper(...) {
    return false;
}

// If passing {From...} as an arg to conversion_test<To> succeeds, beat the ellipsis and return true.
template<typename To, typename... From>
constexpr auto sfinae_helper(int) 
  -> decltype(conversion_test<To>({std::declval<From>()...}), true) {
    return true;
}

// Fall back to the standard trait when possible. You might want to make this name a struct for consistency.
template<typename To, typename... From>
constexpr bool is_multi_convertible_to() {
    if constexpr (sizeof...(From) == 1) {
        return std::is_convertible_v<From..., To>;
    } else {
        return sfinae_helper<To, From...>(0);
    }
}

template<typename To, typename... From>
constexpr bool is_multi_convertible_to_v = is_multi_convertible_to<To, From...>();

struct has_implicit { 
    has_implicit(int, int) {}
};

struct has_explicit {
    explicit has_explicit(int, int) {}
};

// Warning: Not a comprehensive test suite!
static_assert(is_multi_convertible_to_v<int, double>);
static_assert(not is_multi_convertible_to_v<char*, const char*>);
static_assert(is_multi_convertible_to_v<has_implicit, int, int>);
static_assert(not is_multi_convertible_to_v<has_explicit, int, int>);

值得注意的是,Concepts 将删除 sfinae_helper 层,但这应该在 C++17 中有效。千万不要以为它可以完美地工作。

【讨论】:

  • 这太复杂了,尝试在你的类中写一个函数并检查它......
  • @YunfeiChen,我很高兴看到一个更简单的解决方案,它可以编译并执行发布者想要的操作。我不会怀疑那里有更简单的东西。
  • 实际上,我很确定这就是这里的必要条件。在我的问题上测试它似乎可以解决问题(至少对于两个参数构造函数)。谢谢,克里斯!
猜你喜欢
  • 1970-01-01
  • 2014-09-29
  • 1970-01-01
  • 2018-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多