【问题标题】:Variadic template function with more than two parametersvariadic模板函数具有两个以上的参数
【发布时间】:2016-06-30 13:55:57
【问题描述】:

我有以下示例,其中使用了两个参数 t1 和 t2。

template<typename T>
bool Compare(T t1, T t2)
{
    return t1 == t2;
}

template<typename T, typename... Args> 
bool Compare(T t1, T t2, Args...  args)
{
    return (t1 == t2) && Compare(args...);
}

int main(void)
{
    Compare(1, 1, "string", "string");
}

Function Compare 接受相同类型且可以比较的成对参数。 比较两对,然后递归传递参数包,直到达到最后两个参数。 为了停止递归,我使用了不带参数包的比较函数的实现。

我想添加第三个参数 t3 所以函数比较应该是这样的:

template<typename T>
bool Compare(T t1, T t2, T t3)
{
    return t1 == t2 == t3;
}

template<typename T, typename... Args>
bool Compare(T t1, T t2, T t3, Args... args)
{
    return (t1 == t2 == t3) && Compare(args...);
}

int main(void)
{
    Compare(1, 1, 1, "string", "string", "string");
}

我希望这个函数需要三个参数进行比较,然后递归处理接下来的三个。 当我尝试编译此代码时,我收到以下错误:

>xxx\source.cpp(4): error C2446: '==': no conversion from 'const char *' to 'int'
1>  xxx\source.cpp(4): note: There is no context in which this conversion is possible
1>  xxx\source.cpp(10): note: see reference to function template instantiation 'bool Compare<const char*>(T,T,T)' being compiled
1>          with
1>          [
1>              T=const char *
1>          ]
1>  xxx\source.cpp(15): note: see reference to function template instantiation 'bool Compare<int,const char*,const char*,const char*>(T,T,T,const char *,const char *,const char *)' being compiled
1>          with
1>          [
1>              T=int
1>          ]
1>xxx\source.cpp(4): error C2040: '==': 'int' differs in levels of indirection from 'const char *'

如何实现这个函数来比较相同类型的三个参数的集合?

【问题讨论】:

    标签: c++ recursion variadic-templates


    【解决方案1】:
    t1 == t2 == t3
    

    它不检查t1t2t3 是否都相等,它检查t1 是否等于t2,然后检查结果bool 是否等于t3

    也许您想要的是(假设合理的相等运算符):

    t1 == t2 && t1 == t3
    

    所以你的代码应该是这样的:

    template<typename T>
    bool Compare(T t1, T t2, T t3)
    {
        return t1 == t2 && t1 == t3;
    }
    
    template<typename T, typename... Args>
    bool Compare(T t1, T t2, T t3, Args... args)
    {
        return t1 == t2 && t1 == t3 && Compare(args...);
    }
    

    请注意,您使用字符串文字进行的测试调用会进行指针比较,这可能不是您想要的。

    【讨论】:

    • 在最后一行展开:传递包含“string”作为参数之一的 std 字符串的 c_str() 将评估为 false,即使所有字符串都说“string” - 它们具有不同的位置在记忆中。您应该尽可能使用 std 字符串(包括在其中包装字符串常量)。
    【解决方案2】:

    这是我更通用的解决方案。 compareConsecutive&lt;N&gt; 仅当 N 个连续参数对于所有 N 个参数块都相等时才会返回 true。

    #include <iostream>
    #include <tuple>
    #include <utility>
    
    template <std::size_t Start, typename IndexSequence> struct MakeIndexSequenceHelper;
    
    template <std::size_t Start, std::size_t... Is>
    struct MakeIndexSequenceHelper<Start, std::index_sequence<Is...>> {
        using type = std::index_sequence<(Start + Is)...>;
    };
    
    template <std::size_t Start, std::size_t Length>
    struct MakeIndexSequence : MakeIndexSequenceHelper<Start, std::make_index_sequence<Length>> {};
    
    template <typename T, typename U>
    bool allAreSame (const T&, const U&) {
        return false;
    }
    
    template <typename T>
    bool allAreSame (const T& t1, const T& t2) {
        return t1 == t2;
    }
    
    template <typename T, typename U, typename... Args>
    bool allAreSame (const T&, const U&, const Args&...) {
        return false;
    }
    
    template <typename T, typename... Args>
    bool allAreSame (const T& t1, const T& t2, const Args&... args) {
        return allAreSame(t1, t2) && allAreSame(t1, args...);
    }
    
    template <typename Tuple, std::size_t... Is>
    bool allAreSameHelper (Tuple&& tuple, std::index_sequence<Is...>) {
        return allAreSame (std::get<Is>(std::forward<Tuple>(tuple))...);
    }
    
    template <std::size_t N, typename... Args>
    bool allAreSameHelper (Args&&... args) {
        return allAreSameHelper (std::forward_as_tuple(std::forward<Args>(args)...), std::make_index_sequence<N>{});
    }
    
    template <std::size_t N, typename... Args> bool compareConsecutive (Args&&...);
    
    template <std::size_t N>
    bool compareConsecutive() {return true;}
    
    template <std::size_t N, typename Tuple, std::size_t... Is>
    bool compareConsecutiveHelper (Tuple&& tuple, std::index_sequence<Is...>) {
        return compareConsecutive<N> (std::get<Is>(std::forward<Tuple>(tuple))...);
    }
    
    template <std::size_t N, std::size_t Start, std::size_t Length, typename... Args>
    bool compareConsecutiveHelper (Args&&... args) {
        return compareConsecutiveHelper<N> (std::forward_as_tuple(std::forward<Args>(args)...), typename MakeIndexSequence<Start, Length>::type{});
    }
    
    template <std::size_t N, typename... Args> 
    bool compareConsecutive (Args&&... args) {
        return allAreSameHelper<N>(std::forward<Args>(args)...) && compareConsecutiveHelper<N, N, sizeof...(Args) - N>(args...);
    }
    
    int main() {
        std::cout << std::boolalpha << allAreSame("hi", "hi", "hi", "hi", "hi", "hi") << '\n';  // true
        std::cout << compareConsecutive<2>(1, 1, "hi", "hi") << '\n';  // true
        std::cout << compareConsecutive<2>(1, "hi", "hi", "hi") << '\n';  // false
        std::cout << compareConsecutive<3>(1, 1, 1, "hi", "hi", "hi", 4.5, 4.5, 4.5) << '\n';  // true
        std::cout << compareConsecutive<5>(1, 1, 1, 1, 1, "hi", "hi", "hi", "hi", "hi") << '\n';  // true
        std::cout << compareConsecutive<5>(1, 1, 1, 1, 2, "hi", "hi", "hi", "hi", "hi") << '\n';  // false
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-16
      • 1970-01-01
      • 2019-04-20
      • 2019-10-20
      • 2013-08-27
      • 2014-03-15
      • 2020-10-01
      • 1970-01-01
      相关资源
      最近更新 更多